2016-09-12 108 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的東西,我可能已經錯過了。這是非常個人化的,但我更喜歡快速而瘋狂的碰撞,而不是處於未知狀態一段時間,以後在碰撞時更難以調試。