使用RxJava優(yōu)雅的處理服務(wù)器返回異常

實際開發(fā)經(jīng)常有這種情況,比如登錄請求,返回來的并不會僅僅是User對象,而是被包裝的RESTResult<User>對象,RESTResult對象里,包括請求返回的狀態(tài):失敗還是成功,錯誤碼,User對象等等。
如下:

public class RESTResult<T> {
    public static final int FAILURE = 0; // 失敗
    public static final int SUCCESS = 1; // 成功

    private int status;  // 返回狀態(tài):0 失敗   1 成功
    private HttpResponseCode code;  // 錯誤碼
    private String message;  // 返回信息
    private T data;  // 包裝的對象

    // 其他省略
    .... 

在使用Retrofit+RxJava的情況下,以登錄為例,ApiService如下:

public interface ApiService {
    @FormUrlEncoded
    @POST(API + "account/login")
    Observable<RESTResult<User>> login(@Field("mobile") String mobile, @Field("code") String code);
}

我們對于登錄返回的結(jié)果會這樣處理:如果status為SUCCESS,則獲取到User對象并進(jìn)行后續(xù)操作;如果status為FAILURE,則需要根據(jù)code或者message提示用戶相應(yīng)的錯誤提示,并隱藏進(jìn)度條對話框等操作。

下面有2種處理方式,方案1是我們沒接觸或剛接觸Rx時會想到的方案,方案2里是比較優(yōu)雅的處理方式 :)
方案1:

    _apiService.login(mobile, verifyCode)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .doOnTerminate(() -> hideLoadingDialog())
            .subscribe(new Action1<RESTResult<User>>() {
                @Override
                public void call(RESTResult<User> userRESTResult) {
                    if (result.getStatus() == RESTResult.FAILURE) {
                        HttpResponseCode code = result.getCode();
                        // 根據(jù)不同code進(jìn)行不同處理
                        ...
                        Toast.makeText(_context, result.getMessage(), Toast.LENGTH_SHORT).show();
                    } else {
                        User user = result.getData();
                        ...
                    }
                }
            }, new Action1<Throwable>() {
                @Override
                public void call(Throwable throwable) {
                    throwable.printStackTrace();
                    Toast.makeText(_context, "請求失敗,請稍后重試", Toast.LENGTH_SHORT).show();
                }
            });

顯然這個方案有太多缺點(diǎn):
1、RxJava建議在subscribe的時候,觀察者應(yīng)該拿到的是加工完成的數(shù)據(jù)源,而不是未加工的數(shù)據(jù)源;
2、在服務(wù)器返回status=FAILURE的情況下,異常是在onNext里處理,這樣并不合適;
3、判斷RESTResult的部分更應(yīng)該放在鏈?zhǔn)讲僮骼铩?br> 我們需要炫酷的Rx操作符!

最佳體驗:

方案2:使用Observable.error(e):

    _apiService.login(mobile, verifyCode)
            .// 略  顯示提示框、切換線程
            .flatMap(result -> {
                if (result.getStatus() == RESTResult.FAILURE) {
                    HttpResponseCode code = result.getCode();
                    // 根據(jù)不同code進(jìn)行不同處理
                    ...
                 
                    return Observable.error(new ServerException(result.getMessage()));
                }
                return Observable.just(result.getData());
            })
            .subscribe(new Action1<User>() {
                    @Override
                    public void call(User user) {
                       // user對象
                    }
              }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        throwable.printStackTrace();

                        if (e instanceof ServerException){
                           Toast.makeText(_context, e.getMessage(), Toast.LENGTH_SHORT).show();
                        } else{
                           Toast.makeText(_context, "請求失敗,請稍后重試", Toast.LENGTH_SHORT).show();
                        }
                    }  
              });

flaMap操作符可以接收一個Observable的輸出作為輸入,同時輸出另外一個Observable。在服務(wù)器返回status=FAILURE的情況下,返回Observable.error(Throwable exception),SUCCESS的話,just源數(shù)據(jù)為一個新的Observable返回。

Observable.error(Throwable exception):

Returns an Observable that invokes an Observer's onError method when the Observer subscribes to it.

該方法是返回一個Observable,當(dāng)觀察者訂閱時,執(zhí)行觀察者的onError方法。

這個方案完美的解決了方案1、2的問題:
1、觀察者拿到“加工”完成的數(shù)據(jù)源;
2、異常方面,不管是服務(wù)器異常還是其他異常情況,最終觀察者都可以接收到異常數(shù)據(jù)源,并最終統(tǒng)一在onError里處理。
3、使用flatMap處理RESTResult部分的代碼,可以放在任意線程處理

最后:

方案2通過合適的封裝,都可達(dá)到代碼簡化的目的。
封裝部分可以查看我這篇簡書:RxJava簡潔封裝之道

通過RxJava的鏈?zhǔn)讲僮?,結(jié)合恰當(dāng)?shù)牟僮鞣粌H可以把正常的數(shù)據(jù)源發(fā)射給觀察者,同時也可以將錯誤異常數(shù)據(jù)源發(fā)射給觀察者,RxJava遠(yuǎn)比想象中的強(qiáng)大!

方案2是目前我發(fā)現(xiàn)的最合適方案,如果還有更好的解決方案,歡迎告訴我哈~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容