RxJava:如何从flatMap运算符中的错误中恢复

时间:2015-11-10 15:00:16

标签: android rx-java rx-android

我有EditText用户输入搜索查询,我想在用户输入内容时在我的服务器上执行即时搜索。

我尝试使用RxJava执行此操作,如下所示:

RxTextView.textChanges(editQuery) // I'm using RxBinding for listening to text changes
    .flatMap(new Func1<CharSequence, Observable<UserPublic[]>>() {
        @Override
        public Observable<UserPublic[]> call(CharSequence query) {
            return api.searchUsers(query); // I'm using Retrofit 1.9 for network calls. searchUsers returns an Observable<UserPublic[]>
        }
    })
    .subscribe(Observers.create(
        new Action1<UserPublic[]>() {
            @Override
            public void call(UserPublic[] userPublics) {
                processResult(userPublics);
            }
        })
        , new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                processError(throwable);
            }
    });

问题是如果网络调用遇到错误,整个observable都会停止。因此,当用户继续输入时,没有任何反应。

如何修改此代码,以便:

  1. 每当出现网络问题时,都会调用processError
  2. 但是当用户继续输入时,会继续发出新的网络电话(再次导致processResult / processError

2 个答案:

答案 0 :(得分:2)

使用retryWhen()运算符并在订阅之前将其附加到可观察链。请注意,retryWhen()的参数是一个带Observable<Throwable>并返回Observable<?>的函数。返回的类型无关紧要,因为运算符使用onNext()结果启动重试,onError()onCompleted()结果终止链。

这是一个等待5秒并再次尝试的天真应用程序:

observable
  .retryWhen( errorObservable -> errorObservable.delay( 5, TimeUnit.SECONDS ) )
  .subscribe();

这是一个不那么天真的操作,会在超时时重试,如果发生IOException则会失败:

observable
  .retryWhen( errorObservable -> errorObservable.flatMap( throwable -> { // (1)
       if ( throwable instanceof IOException ) {
         return Observable.error( throwable ); // (2)
       }
       return Observable.just(1); // (3)
     } )
  .subscribe();
  1. 使用flatMap()可以让您推迟决定,直到您知道要处理的是哪种错误。
  2. 返回的observable会抛出提供的错误或其他您想要更好地描述问题的内容。
  3. 提供一个只有onNext()的观察者告诉retryWhen()运营商重新订阅原始观察结果。

答案 1 :(得分:0)

我建议您查看RxJava文档中的Error Handling Operators页面。尝试与不同的操作员一起提出最适合您的用例的操作员。我认为您应该使用onErrorResumeNext()返回的某种默认值,例如返回new UserPublic[0]。在这里调用processError会有问题,特别是如果它处理UI,因为您可能仍在后台线程上进行处理。