本文內(nèi)容是基于Retrofit + RxJava做的一些巧妙的封裝。主要講解針對網(wǎng)絡(luò)請求的錯誤信息進行一次封裝,方便我們根據(jù)返回的狀態(tài)合理地在UI界面進行顯示。并結(jié)合上篇文章對Retrofit的配置。對RxJava+Retrofit網(wǎng)絡(luò)請求使用進行的封裝,包括緩存處理,請求異常處理等內(nèi)容,使用大多數(shù)網(wǎng)絡(luò)請求狀況,即拽即用。可以去最下面的地址下載代碼。
本文內(nèi)容是基于RxJava 2.0及Retrofit 2.1分析的。參考了Rxjava +Retrofit 你需要掌握的幾個技巧,Retrofit緩存,統(tǒng)一對有無網(wǎng)絡(luò)處理, 異常處理,返回結(jié)果問題
下面列出具體添加的依賴。
//引入okhttp
compile 'com.squareup.okhttp3:okhttp:3.5.0'
//引入retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'
//引入rxjava
compile 'io.reactivex.rxjava2:rxjava:2.0.4'
//引入Log攔截器,方便DEBUG模式輸出log信息
compile 'com.squareup.okhttp3:logging-interceptor:3.5.0'
//引入rxjava適配器,方便rxjava與retrofit的結(jié)合
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
//引入json轉(zhuǎn)換器,方便將返回的數(shù)據(jù)轉(zhuǎn)換為json格式
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
//引入rxandroid
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
異常處理的必要性
以下這些錯誤,都是在網(wǎng)絡(luò)請求中經(jīng)常見的。我們可以通過Toast彈出消息通知用戶具體的異常以及加載對應(yīng)的UI界面。除此之外,通過具體的異常信息,方便我們及時的排查項目中的BUG。
那么問題就來了,我們?nèi)绾闻袛喈惓5念愋停?/p>
這就要從服務(wù)器返回的數(shù)據(jù)格式說起了。
我們一般請求的返回都是像下面這樣
{
"code":"200",
"message":"Return Successd!",
"data":{
"name":"張三"
"age":3
}
}
服務(wù)器端返回數(shù)據(jù)約定俗稱就是大概以上的格式。可能具體的code碼表示的含義不一樣,這個可以與服務(wù)器端人員交流,靈活變化。
關(guān)于Retrofit的基本配置就不再講述了,可以看我的另一篇文章。這里具體講解如何對服務(wù)器返回數(shù)據(jù)封裝以及使用RxJava對錯誤信息處理。
封裝返回數(shù)據(jù)及異常類型判斷
封裝返回數(shù)據(jù)
對于上述的服務(wù)器返回數(shù)據(jù)我們要對code做出一些判斷,code不為200(假設(shè)200表示請求網(wǎng)絡(luò)成功)就拋出異常。所以我們新建一個BaseResponse類,對應(yīng)上面的數(shù)據(jù)結(jié)構(gòu)。
public class BaseResponse<T> {
private int code;
private String msg;
private T data;
//該方法假設(shè)服務(wù)器返回200表示成功返回結(jié)果,其他數(shù)字表示異常
public boolean isOk() {
return code ==200;
}
//省略getter,setter方法
}
這算是所有實體的一個基類,data可以為任何數(shù)據(jù)類型。
然后要對返回結(jié)果進行預(yù)處理,新建一個ExceptionHandle。預(yù)處理無非就是當(dāng)根據(jù)返回數(shù)據(jù)BaseResponse的isOk()方法判斷為是否為true,若為true則正常處理,否則拋出異常讓ExceptionHandle進一步處理,判斷異常為何種異常。我們先跳過前面的邏輯,先了解如何判斷是何種異常?
判斷異常類型
public class ExceptionHandle {
//該方法用來判斷異常類型 并將異常類型封裝在ResponeThrowable返回
public static ResponeThrowable handleException(Throwable e) {
if (e instanceof HttpException) {
HttpException httpException = (HttpException) e;
ex = new ResponeThrowable(e, ERROR.HTTP_ERROR);
ex.message = "網(wǎng)絡(luò)錯誤";
return ex;
}
...................
...................其他類型異常判斷
...................
}
}
詳細(xì)可看源碼,下面會貼出地址。
通過ExceptionHandle.handleException(Throwable e) 即可返回一個異常,并攜帶具體異常類型信息。
現(xiàn)在我們已經(jīng)知道了如何判斷是否產(chǎn)生以上以及如何判斷異常類型。接下來需要解決地就是如何把異常傳遞給Observer的onError(Throwable e)去處理異常。
異常傳遞
在進行異常傳遞的過程中,第一步我們先要判斷服務(wù)器返回的數(shù)據(jù)是否是異常,如果不是異常則返回data數(shù)據(jù),如果是異常則拋出異常。這個時候就包含了一個數(shù)據(jù)轉(zhuǎn)換的過程即把BaseResponse對象轉(zhuǎn)換成data類型的對象,所以需要map()操作符。
(Observable<T>) upstream.map(new HandleFuc<T>())
其中HandleFuc實現(xiàn)了Function<BaseResponse<T>, T>
接口
public static class HandleFuc<T> implements Function<BaseResponse<T>, T> {
@Override
public T apply(BaseResponse<T> response) throws Exception {
//response中code碼不為200 出現(xiàn)錯誤
if (!response.isOk())
//拋出異常,把狀態(tài)碼及狀態(tài)描述信息傳入
throw new RuntimeException(response.getCode() + "" + response.getMsg() != null ? response.getMsg() : "");
return response.getData();
}
}
如果不出現(xiàn)異常則不會走第二步。如果出現(xiàn)異常,則需要進行第二步,即對異常進行判斷,然后將ExceptionHandle.handleException(Throwable e) 返回的異常傳入onError()中處理。
重點來了:當(dāng)產(chǎn)生異常時,應(yīng)該終止對onNext()方法的調(diào)用并調(diào)用onError()方法。如果不繼續(xù)處理,僅通過以上步驟,雖然會調(diào)用onError()方法,但是沒有對異常進行判斷,并且沒有取消onNext()方法。那么有沒有一個好的方法,可以即取消onNext()方法,又能在其中實現(xiàn)異常判斷的執(zhí)行,并且會調(diào)用onError()方法?
如此強大的RxJava自然有這樣的方法了,onErrorResumeNext()
就能實現(xiàn)這個要求。對于onErrorResumeNext()
,可以簡單理解為:當(dāng)發(fā)生錯誤的時候,由另外一個Observable來代替當(dāng)前的Observable并繼續(xù)發(fā)射數(shù)據(jù)。
onErrorResumeNext()
中傳入的參數(shù)可以是一個Function接口。這樣,我們可以在Function中生成一個Observable,該Observable執(zhí)行異常判斷的邏輯,并調(diào)用onError()方法。
具體實現(xiàn)如下:
(Observable<T>) upstream.map(new HandleFuc<T>()).onErrorResumeNext(new HttpResponseFunc<T>());
public static class HttpResponseFunc<T> implements Function<Throwable, Observable<T>> {
@Override
public Observable<T> apply(Throwable throwable) throws Exception {
return Observable.error(ExceptionHandle.handleException(throwable));
}
}
至此,我們便實現(xiàn)了異常判斷與傳遞的邏輯。這樣我們就可以在onError()方法中提取具體的異常狀態(tài)信息,進行相應(yīng)的處理。
大概流程是:map()進行數(shù)據(jù)類型轉(zhuǎn)換,并檢測異常。如果正常,返回data類型的數(shù)據(jù)。如果不正常,onErrorResumeNext()判斷異常類型并傳遞異常
下面展示一個簡單的效果圖:
上述情況關(guān)閉了網(wǎng)絡(luò)。當(dāng)發(fā)起網(wǎng)絡(luò)請求,沒有網(wǎng)絡(luò)則拋出異常,然后檢測出具體異常,Toast提示異常類型,用戶便知道是什么地方出錯了。
結(jié)合上篇文章對Retrofit的配置。對RxJava+Retrofit網(wǎng)絡(luò)請求使用進行的封裝,包括緩存處理,請求異常處理等內(nèi)容,使用大多數(shù)網(wǎng)絡(luò)請求狀況,即拽即用。可以去下面的地址下載代碼。
代碼地址