本文內(nèi)容是基于Retrofit + RxJava做的一些巧妙的封裝骂际。主要講解針對(duì)網(wǎng)絡(luò)請(qǐng)求的錯(cuò)誤信息進(jìn)行一次封裝闷尿,方便我們根據(jù)返回的狀態(tài)合理地在UI界面進(jìn)行顯示老充。并結(jié)合上篇文章對(duì)Retrofit的配置列粪。對(duì)RxJava+Retrofit網(wǎng)絡(luò)請(qǐng)求使用進(jìn)行的封裝福侈,包括緩存處理酒来,請(qǐng)求異常處理等內(nèi)容,使用大多數(shù)網(wǎng)絡(luò)請(qǐng)求狀況肪凛,即拽即用堰汉。可以去最下面的地址下載代碼伟墙。
本文內(nèi)容是基于RxJava 2.0及Retrofit 2.1分析的翘鸭。參考了Rxjava +Retrofit 你需要掌握的幾個(gè)技巧,Retrofit緩存戳葵,統(tǒng)一對(duì)有無網(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'
異常處理的必要性
以下這些錯(cuò)誤,都是在網(wǎng)絡(luò)請(qǐng)求中經(jīng)常見的邦投。我們可以通過Toast彈出消息通知用戶具體的異常以及加載對(duì)應(yīng)的UI界面伤锚。除此之外,通過具體的異常信息志衣,方便我們及時(shí)的排查項(xiàng)目中的BUG屯援。
那么問題就來了,我們?nèi)绾闻袛喈惓5念愋停?/p>
這就要從服務(wù)器返回的數(shù)據(jù)格式說起了念脯。
我們一般請(qǐng)求的返回都是像下面這樣
{
"code":"200",
"message":"Return Successd!",
"data":{
"name":"張三"
"age":3
}
}
服務(wù)器端返回?cái)?shù)據(jù)約定俗稱就是大概以上的格式狞洋。可能具體的code碼表示的含義不一樣绿店,這個(gè)可以與服務(wù)器端人員交流徘铝,靈活變化。
關(guān)于Retrofit的基本配置就不再講述了惯吕,可以看我的另一篇文章惕它。這里具體講解如何對(duì)服務(wù)器返回?cái)?shù)據(jù)封裝以及使用RxJava對(duì)錯(cuò)誤信息處理。
封裝返回?cái)?shù)據(jù)及異常類型判斷
封裝返回?cái)?shù)據(jù)
對(duì)于上述的服務(wù)器返回?cái)?shù)據(jù)我們要對(duì)code做出一些判斷废登,code不為200(假設(shè)200表示請(qǐng)求網(wǎng)絡(luò)成功)就拋出異常淹魄。所以我們新建一個(gè)BaseResponse類,對(duì)應(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方法
}
這算是所有實(shí)體的一個(gè)基類,data可以為任何數(shù)據(jù)類型羽戒。
然后要對(duì)返回結(jié)果進(jìn)行預(yù)處理缤沦,新建一個(gè)ExceptionHandle。預(yù)處理無非就是當(dāng)根據(jù)返回?cái)?shù)據(jù)BaseResponse的isOk()方法判斷為是否為true易稠,若為true則正常處理缸废,否則拋出異常讓ExceptionHandle進(jìn)一步處理,判斷異常為何種異常驶社。我們先跳過前面的邏輯企量,先了解如何判斷是何種異常?
判斷異常類型
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ò)錯(cuò)誤";
return ex;
}
...................
...................其他類型異常判斷
...................
}
}
詳細(xì)可看源碼亡电,下面會(huì)貼出地址届巩。
通過ExceptionHandle.handleException(Throwable e) 即可返回一個(gè)異常,并攜帶具體異常類型信息份乒。
現(xiàn)在我們已經(jīng)知道了如何判斷是否產(chǎn)生以上以及如何判斷異常類型恕汇。接下來需要解決地就是如何把異常傳遞給Observer的onError(Throwable e)去處理異常腕唧。
異常傳遞
在進(jìn)行異常傳遞的過程中,第一步我們先要判斷服務(wù)器返回的數(shù)據(jù)是否是異常瘾英,如果不是異常則返回data數(shù)據(jù)枣接,如果是異常則拋出異常。這個(gè)時(shí)候就包含了一個(gè)數(shù)據(jù)轉(zhuǎn)換的過程即把BaseResponse對(duì)象轉(zhuǎn)換成data類型的對(duì)象方咆,所以需要map()操作符。
(Observable<T>) upstream.map(new HandleFuc<T>())
其中HandleFuc實(shí)現(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)錯(cuò)誤
if (!response.isOk())
//拋出異常蟀架,把狀態(tài)碼及狀態(tài)描述信息傳入
throw new RuntimeException(response.getCode() + "" + response.getMsg() != null ? response.getMsg() : "");
return response.getData();
}
}
如果不出現(xiàn)異常則不會(huì)走第二步瓣赂。如果出現(xiàn)異常,則需要進(jìn)行第二步片拍,即對(duì)異常進(jìn)行判斷煌集,然后將ExceptionHandle.handleException(Throwable e) 返回的異常傳入onError()中處理。
重點(diǎn)來了:當(dāng)產(chǎn)生異常時(shí)捌省,應(yīng)該終止對(duì)onNext()方法的調(diào)用并調(diào)用onError()方法苫纤。如果不繼續(xù)處理,僅通過以上步驟纲缓,雖然會(huì)調(diào)用onError()方法卷拘,但是沒有對(duì)異常進(jìn)行判斷,并且沒有取消onNext()方法祝高。那么有沒有一個(gè)好的方法栗弟,可以即取消onNext()方法,又能在其中實(shí)現(xiàn)異常判斷的執(zhí)行工闺,并且會(huì)調(diào)用onError()方法乍赫?
如此強(qiáng)大的RxJava自然有這樣的方法了,onErrorResumeNext()
就能實(shí)現(xiàn)這個(gè)要求陆蟆。對(duì)于onErrorResumeNext()
雷厂,可以簡(jiǎn)單理解為:當(dāng)發(fā)生錯(cuò)誤的時(shí)候,由另外一個(gè)Observable來代替當(dāng)前的Observable并繼續(xù)發(fā)射數(shù)據(jù)叠殷。
onErrorResumeNext()
中傳入的參數(shù)可以是一個(gè)Function接口改鲫。這樣,我們可以在Function中生成一個(gè)Observable林束,該Observable執(zhí)行異常判斷的邏輯钩杰,并調(diào)用onError()方法。
具體實(shí)現(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));
}
}
至此诊县,我們便實(shí)現(xiàn)了異常判斷與傳遞的邏輯讲弄。這樣我們就可以在onError()方法中提取具體的異常狀態(tài)信息,進(jìn)行相應(yīng)的處理依痊。
大概流程是:map()進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換避除,并檢測(cè)異常怎披。如果正常,返回data類型的數(shù)據(jù)瓶摆。如果不正常凉逛,onErrorResumeNext()判斷異常類型并傳遞異常
下面展示一個(gè)簡(jiǎn)單的效果圖:
上述情況關(guān)閉了網(wǎng)絡(luò)。當(dāng)發(fā)起網(wǎng)絡(luò)請(qǐng)求群井,沒有網(wǎng)絡(luò)則拋出異常状飞,然后檢測(cè)出具體異常,Toast提示異常類型书斜,用戶便知道是什么地方出錯(cuò)了诬辈。
結(jié)合上篇文章對(duì)Retrofit的配置。對(duì)RxJava+Retrofit網(wǎng)絡(luò)請(qǐng)求使用進(jìn)行的封裝荐吉,包括緩存處理焙糟,請(qǐng)求異常處理等內(nèi)容,使用大多數(shù)網(wǎng)絡(luò)請(qǐng)求狀況样屠,即拽即用穿撮。可以去下面的地址下載代碼痪欲。
代碼地址