Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/212.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
android rxJava:如何从缓存中获取数据,同时在后台进行更新?_Android_Rx Java - Fatal编程技术网

android rxJava:如何从缓存中获取数据,同时在后台进行更新?

android rxJava:如何从缓存中获取数据,同时在后台进行更新?,android,rx-java,Android,Rx Java,我刚刚开始学习Android的rxJava,并希望实现常见用例: 从缓存请求数据并显示给用户 从web请求数据 服务器更新存储中的数据并自动向用户显示 传统上,最好的方案之一是使用CursorLoader从缓存中获取数据,在单独的线程中运行web请求,并通过内容提供程序将数据保存到磁盘,内容提供程序自动通知侦听器和CursorLoader自动更新UI 在rxJava中,我可以通过运行两个不同的观察者来实现这一点,正如您在下面的代码中所看到的,但我没有找到如何将这两个调用合并到一个调用中以达到

我刚刚开始学习Android的rxJava,并希望实现常见用例:

  • 从缓存请求数据并显示给用户
  • 从web请求数据
  • 服务器更新存储中的数据并自动向用户显示
传统上,最好的方案之一是使用CursorLoader从缓存中获取数据,在单独的线程中运行web请求,并通过内容提供程序将数据保存到磁盘,内容提供程序自动通知侦听器和CursorLoader自动更新UI

在rxJava中,我可以通过运行两个不同的观察者来实现这一点,正如您在下面的代码中所看到的,但我没有找到如何将这两个调用合并到一个调用中以达到我的目标的方法。Google显示了这个线程,但看起来它只是从缓存中获取数据或从web服务器获取数据,但不要同时执行这两个操作

代码段:

@Override
public Observable<SavingsGoals> getCachedSavingsGoal() {
    return observableGoal.getSavingsGoals()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread());
}

@Override
public Observable<SavingsGoals> getRecentSavingsGoal() {
    return api.getSavingsGoals()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread());
}

    model.getCachedSavingsGoal().subscribe(new Observer<SavingsGoals>() {
        @Override
        public void onCompleted() {
            // no op
        }

        @Override
        public void onError(Throwable e) {
            Log.e(App.TAG, "Failed to consume cached data");
            view.showError();
        }

        @Override
        public void onNext(SavingsGoals savingsGoals) {
            Log.d(App.TAG, "Show the next item");
            if (savingsGoals != null && !savingsGoals.getSavingsGoals().isEmpty()) {
                view.showData(savingsGoals.getSavingsGoals());
            } else {
                view.showError();
            }
        }
    });

    model.getRecentSavingsGoal().subscribe(new Observer<SavingsGoals>() {
        @Override
        public void onCompleted() {
            // no op
        }

        @Override
        public void onError(Throwable e) {
            Log.e(App.TAG, "Failed to consume data from the web", e);
            view.showError();
        }

        @Override
        public void onNext(SavingsGoals savingsGoals) {
            if (savingsGoals != null && !savingsGoals.getSavingsGoals().isEmpty()) {
                view.showData(savingsGoals.getSavingsGoals());
            } else {
                view.showError();
            }
        }
    });
@覆盖
公共可观测getCachedSavingsGoal(){
return observegoal.getSavingsGoals()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
@凌驾
公共可观察getRecentSavingsGoal(){
返回api.getSavingsGoals()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
model.getCachedSavingsGoal().subscribe(新观察者(){
@凌驾
未完成的公共无效(){
//无操作
}
@凌驾
公共无效申报人(可丢弃的e){
Log.e(App.TAG,“无法使用缓存数据”);
view.ror();
}
@凌驾
公共无效onNext(储蓄利息储蓄利息){
Log.d(App.TAG,“显示下一项”);
if(savingsGoals!=null&!savingsGoals.getSavingsGoals().isEmpty()){
view.showData(savingsGoals.getSavingsGoals());
}否则{
view.ror();
}
}
});
model.getRecentSavingsGoal().subscribe(新观察者()){
@凌驾
未完成的公共无效(){
//无操作
}
@凌驾
公共无效申报人(可丢弃的e){
Log.e(App.TAG,“未能使用来自web的数据”,e);
view.ror();
}
@凌驾
公共无效onNext(储蓄利息储蓄利息){
if(savingsGoals!=null&!savingsGoals.getSavingsGoals().isEmpty()){
view.showData(savingsGoals.getSavingsGoals());
}否则{
view.ror();
}
}
});
此外,当前方法的一个问题是缓存和web数据不能保证连续运行。当过时的数据以最新的形式出现并覆盖来自web的最新数据时,这是可能的

为了解决这个问题,我实现了观测者合并和按时间戳过滤:它从缓存中获取数据,将数据传递给下一个观测者,如果缓存过时,则向web案例发出新的调用,以通过按时间戳过滤解决线程竞争问题。然而,这种方法的问题是我无法从这个可观察对象返回缓存数据——我需要等待两个请求完成它们的工作

代码片段

    @Override
public Observable<Timestamped<SavingsGoals>> getSavingGoals() {
    return observableGoal
            .getTimestampedSavingsGoals()
            .subscribeOn(Schedulers.io())
            .flatMap(new Func1<Timestamped<SavingsGoals>, Observable<Timestamped<SavingsGoals>>>() {
                @Override
                public Observable<Timestamped<SavingsGoals>> call(Timestamped<SavingsGoals> cachedData) {
                    Log.d(App.FLOW, "getTimestampedSavingsGoals");
                    return getGoalsFromBothSources()
                            .filter(filterResponse(cachedData));
                }
            })
            .subscribeOn(AndroidSchedulers.mainThread());
}

private Func1<Timestamped<SavingsGoals>, Boolean> filterResponse(Timestamped<SavingsGoals> cachedData) {
    return new Func1<Timestamped<SavingsGoals>, Boolean>() {
        @Override
        public Boolean call(Timestamped<SavingsGoals> savingsGoals) {
            return savingsGoals != null
                    && cachedData != null
                    && cachedData.getTimestampMillis() < savingsGoals.getTimestampMillis()
                    && savingsGoals.getValue().getSavingsGoals().size() != 0;
        }
    };
}

private Observable<Timestamped<SavingsGoals>> getGoalsFromBothSources() {
    Log.d(App.FLOW, "getGoalsFromBothSources:explicit");
    return Observable.merge(
            observableGoal.getTimestampedSavingsGoals().subscribeOn(Schedulers.io()),
            api.getSavingsGoals()
                    .timestamp()
                    .flatMap(new Func1<Timestamped<SavingsGoals>, Observable<Timestamped<SavingsGoals>>>() {
                        @Override
                        public Observable<Timestamped<SavingsGoals>> call(Timestamped<SavingsGoals> savingsGoals) {
                            Log.d(App.FLOW, "getGoalsFromBothSources:implicit");
                            return observableGoal.saveAllWithTimestamp(savingsGoals.getTimestampMillis(), savingsGoals.getValue().getSavingsGoals());
                        }
                    }))
                    .subscribeOn(Schedulers.io());
}
@覆盖
公众可观察的getSavingGoals(){
回归自我
.getTimestampedSavingsGoals()
.subscribeOn(Schedulers.io())
.flatMap(新函数1(){
@凌驾
公共可观察调用(带时间戳的cachedData){
Log.d(App.FLOW,“getTimestampedSavingsGoals”);
返回getGoalsFromBothSources()
.filter(filterResponse(cachedData));
}
})
.subscribeOn(AndroidSchedulers.mainThread());
}
private Func1 filterResponse(带时间戳的cachedData){
返回新的Func1(){
@凌驾
公共布尔调用(带时间戳的savingsGoals){
返回savingsGoals!=null
&&cachedData!=null
&&cachedData.getTimestampMillis()
你知道在一个观察者身上做这件事的方法吗

潜在解决方案:

@Override
public Observable<SavingsGoals> getSavingGoals() {
    return api.getSavingsGoals()
            .publish(network ->
                    Observable.mergeDelayError(
                            observableGoal.getSavingsGoals().takeUntil(network),
                            network.flatMap(new Func1<SavingsGoals, Observable<SavingsGoals>>() {
                                @Override
                                public Observable<SavingsGoals> call(SavingsGoals savingsGoals) {
                                    return observableGoal.saveAll(savingsGoals.getSavingsGoals());
                                }
                            })
                    )
            )
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread());
}
@覆盖
公众可观察的getSavingGoals(){
返回api.getSavingsGoals()
.发布(网络->
可观测误差(
observegegoal.getSavingsGoals().takeUntil(网络),
network.flatMap(新的Func1(){
@凌驾
公共可观察呼叫(SavingsGoals SavingsGoals){
返回observegoal.saveAll(savingsGoals.getSavingsGoals());
}
})
)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
  • 抱歉,ID中的热替换
    public Observable<NetworkResponse> getDataFromNetwork(
          final Request request) {
        return networkCall.doOnNext(networkResponse -> saveToStorage(networkResponse);
      }
    
      public Observable<Response> getData(final Request request) {
    
        return dataService.getDataFromNetwork(request)
            .publish(networkResponse ->  Observable.merge(networkResponse, dataService.getDataFromStorage(request).takeUntil(networkResponse)));
      }
    
      public Observable<Response> getData(final Request request) {
    
        return dataService.getDataFromNetwork(request)
            .publish(networkResponse ->  Observable.merge(networkResponse, dataService.getDataFromStorage(request).takeUntil(networkResponse)))
            .onErrorResumeNext(dataService.getDataFromStorage(request);
      }
    
    @Nonnull
    public Observable<SomeData> getSomeDataObservable() {
        return Observable
                .defer(new Func0<Observable<SomeData>>() {
                    @Override
                    public Observable<SomeData> call() {
                        return Observable.just(getSomeData());
                    }
                });
    }
    
    @Nonnull
    public Observable<SomeData> getSomeDataObservableRefreshable() {
        return refreshSubject.startWith((Object)null).switchMap(new Func1() {
            public Observable<T> call(Object o) {
                return getSomeDataObservable();
            }
        }     
    }
    
    @Nonnull
    public Observable<SomeData> getSomeDataObservable() {
        return Observable
                .defer(new Func0<Observable<SomeData>>() {
                    @Override
                    public Observable<SomeData> call() {
                        return Observable.just(getSomeData());
                    }
                })
                .compose(MoreOperators.<SomeData>refresh(refreshSubject));
    }