2016-09-12 81 views
2

我正在使用RxJava和Retrofit2(以OkHttp作为HTTP客户端)进行网络连接,并试图了解Retrofit2如何处理不同的错误以及它们如何从RxJava端看。以下代码说明了网络调用的RxJava订阅者回调(使用Retrofit进行)。Retrofit2 + RxJava错误处理

 Subscription subscription = observable 
      .subscribeOn(mScheduler) 
      .observeOn(mAndroidScheduler) 
      .subscribe(new Subscriber<User>() { 
       @Override 
       public void onCompleted() { 
        Timber.d("onCompleted called"); 
        mRetainerView.clearUserObservable(); 
        mActivityView.hideProgressBar(); 
        mActivityView.enableUi(); 
       } 

       @Override 
       public void onError(Throwable e) { 
        Timber.d("onError called"); 
        Timber.d(e.toString()); 
        mRetainerView.clearUserObservable(); 
        mActivityView.hideProgressBar(); 
        mActivityView.enableUi(); 
       } 

       @Override 
       public void onNext(User user) { 
        Timber.d("onNext called"); 
        mRetainerView.clearUserObservable(); 
        mActivityView.hideProgressBar(); 
        mActivityView.enableUi(); 
        mActivityView.launchMainActivity(); 
       } 
      }); 

我的问题是,在什么情况下会onerror的()被调用,一旦它被调用时,我怎么可以询问的Throwable,以确定原因是什么?

根据Retrofit源代码,它看起来像唯一可以看到的Throwables是IOException和HttpException。任何人都可以验证这是真的吗?

回答

5

这里的基础知识:onError()将被调用,如果:

  • observable你订阅抛出异常(例如,你得到一个IOException尝试读取文件)
  • 将引发异常在你的onNext()方法中。

如果在你的onComplete()异常,RxJava将传播的rx.exceptions.OnCompletedFailedException,如果有一个例外,在onError() - 你会得到rx.exceptions.OnErrorFailedException。也就是说,您可以探索您在onError()方法中收到的Throwable,以了解您期望的异常情况。例如,您知道如果您的API调用导致客户端错误(4xx),则Retrofit会将其包装为HttpException。如果请求超时,您将获得SocketTimeoutException。下面是一个粗略的例子:

@Override 
public void onError(Throwable e) { 
    Timber.d("onError called"); 
    Timber.d(e.toString()); 
    handleError(e); 
} 

private handleError(Throwable throwable) { 
    if (throwable instanceof HttpException) { 
     HttpException httpException = (HttpException)throwable; 
     int statusCode = httpException.code(); 
     // handle different HTTP error codes here (4xx) 
    } else if (throwable instanceof SocketTimeoutException) { 
     // handle timeout from Retrofit 
    } else if (throwable instanceof IOException) { 
     // file was not found, do something 
    } else { 
     // generic error handling 
     mRetainerView.clearUserObservable(); 
     mActivityView.hideProgressBar(); 
     mActivityView.enableUi(); 
} 
0

请勿使用onError进行设置。对于流量来说,这将和try-catch一样糟糕。

错误的HTTP代码,是有效的答复,你不应该在onError处理它们。 您可以在Result中包装您的Retrofit服务的退货类型,这样可以让您获得有关您的调用发生的情况的信息,而不会抛出异常。

您可以使用这种模式处理您的应用程序的状态:

service.getSomething() 
     .map(r -> Model.success(r.response())) 
     .onErrorReturn(Model::error) 
     .observeOn(AndroidSchedulers.mainThread()) 
     .startWith(Resource.loading()) 
     .subscribe(r -> { 
      myProgressBar.setVisible(r.isLoading()); 
      if (r.isSuccess()) { 
       handleSuccess(); // e.g. 400 is also success but needs handling 
      } 
      if (r.isError()) { 
       handleError(); 
      } 
     }, OnErrorNotImplementedException::new); 

看我如何试图处理数据流中的所有可能的状态和故意我扔OnErrorNotImplementedException的东西,我可能已经错过了。这是非常个人化的,但我更喜欢快速而疯狂的碰撞,而不是处于未知状态一段时间,以后在碰撞时更难以调试。