背景
在前面Rxjava+ReTrofit+okHttp深入淺出-終極封裝專欄我們已經(jīng)全面的封裝了一套可以投入實(shí)戰(zhàn)的框架冠桃,最近開設(shè)了微信群中有兄弟說異常處理這塊可以優(yōu)化優(yōu)化并給出了建議參考項(xiàng)目歇盼,果斷重新將之前的封裝完善走起來舶赔,將請求過程中的處理統(tǒng)一封裝起來湃交,回調(diào)給調(diào)用者熟空,根據(jù)自定義回調(diào)類型方便查詢錯誤類型和信息。
前提
本章的內(nèi)容基于掌握了前面封裝的原理以后搞莺,學(xué)期起來才能完全的理解
RxJava+Retrofit+OkHttp深入淺出-終極封裝專欄
效果:
通過統(tǒng)一的異常處理息罗,可以實(shí)現(xiàn)各種異常的統(tǒng)一處理,然后通過統(tǒng)一回調(diào)給使用者才沧,方便統(tǒng)一展示和顯示提示給用戶
第一條錯誤:故意修改了service里面方法地址迈喉,導(dǎo)致錯誤
第二條錯誤:過期token,服務(wù)器返回的錯誤信息
優(yōu)化之路
1.定義回調(diào)異常類
定義的回調(diào)類温圆,方便回調(diào)接口統(tǒng)一處理挨摸,其中包含錯誤code和錯誤信息displayMessage
public class ApiException extends Exception{
/*錯誤碼*/
private int code;
/*顯示的信息*/
private String displayMessage;
public ApiException(Throwable e) {
super(e);
}
public ApiException(Throwable cause,@CodeException.CodeEp int code, String showMsg) {
super(showMsg, cause);
setCode(code);
setDisplayMessage(showMsg);
}
@CodeException.CodeEp
public int getCode() {
return code;
}
public void setCode(@CodeException.CodeEp int code) {
this.code = code;
}
public String getDisplayMessage() {
return displayMessage;
}
public void setDisplayMessage(String displayMessage) {
this.displayMessage = displayMessage;
}
}
2.定義錯誤碼
自定義錯誤碼,相關(guān)的錯誤碼可以自行設(shè)定規(guī)則岁歉,框架現(xiàn)在給出了常用的錯誤碼定義得运,采用上一章講解的Android注解方式來定義錯誤碼的使用:
public class CodeException {
/*網(wǎng)絡(luò)錯誤*/
public static final int NETWORD_ERROR = 0x1;
/*http_錯誤*/
public static final int HTTP_ERROR = 0x2;
/*fastjson錯誤*/
public static final int JSON_ERROR = 0x3;
/*未知錯誤*/
public static final int UNKNOWN_ERROR = 0x4;
/*運(yùn)行時(shí)異常-包含自定義異常*/
public static final int RUNTIME_ERROR = 0x5;
/*無法解析該域名*/
public static final int UNKOWNHOST_ERROR = 0x6;
@IntDef({NETWORD_ERROR, HTTP_ERROR, RUNTIME_ERROR, UNKNOWN_ERROR, JSON_ERROR, UNKOWNHOST_ERROR})
@Retention(RetentionPolicy.SOURCE)
public @interface CodeEp {
}
}
因?yàn)槭窃?a href="http://www.reibang.com/p/bf949ee41c29" target="_blank">Rxjava+ReTrofit+okHttp深入淺出-終極封裝六特殊篇(變種String替換Gson自由擴(kuò)展)基礎(chǔ)上完善的異常處理,這里解析使用的是 fastjson的異常定義json解析異常
3.完善自定義運(yùn)行時(shí)異常
HttpTimeException
類在之前的封裝中就已經(jīng)存在锅移,通過它在處理服務(wù)器返回錯誤信息和緩存錯誤信息熔掺,所以我們只是完善它的調(diào)用規(guī)則,讓它更加合理
public class HttpTimeException extends RuntimeException {
/*未知錯誤*/
public static final int UNKOWN_ERROR = 0x1002;
/*本地?zé)o緩存錯誤*/
public static final int NO_CHACHE_ERROR = 0x1003;
/*緩存過時(shí)錯誤*/
public static final int CHACHE_TIMEOUT_ERROR = 0x1004;
public HttpTimeException(int resultCode) {
this(getApiExceptionMessage(resultCode));
}
public HttpTimeException(String detailMessage) {
super(detailMessage);
}
/**
* 轉(zhuǎn)換錯誤數(shù)據(jù)
*
* @param code
* @return
*/
private static String getApiExceptionMessage(int code) {
switch (code) {
case UNKOWN_ERROR:
return "錯誤:網(wǎng)絡(luò)錯誤";
case NO_CHACHE_ERROR:
return "錯誤:無緩存數(shù)據(jù)";
case CHACHE_TIMEOUT_ERROR:
return "錯誤:緩存數(shù)據(jù)過期";
default:
return "錯誤:未知錯誤";
}
}
}
完善后:加入code
碼和對應(yīng)的錯誤信息
4.建立異常工廠類
異常工廠類中非剃,通過傳入對應(yīng)的Throwable
錯誤置逻,然后根據(jù)Throwable
的不同類型,生成不同的與之對應(yīng)的ApiException
異常备绽,最后將ApiException
異常返回給最后的rx回調(diào)onerror
方法诽偷,最后onerror
方法統(tǒng)一對異常進(jìn)行處理(如果你的需求又這樣的要求)回調(diào)給用戶界面;
public class FactoryException {
private static final String HttpException_MSG = "網(wǎng)絡(luò)錯誤";
private static final String ConnectException_MSG = "連接失敗";
private static final String JSONException_MSG = "fastjeson解析失敗";
private static final String UnknownHostException_MSG = "無法解析該域名";
/**
* 解析異常
*
* @param e
* @return
*/
public static ApiException analysisExcetpion(Throwable e) {
ApiException apiException = new ApiException(e);
if (e instanceof HttpException) {
/*網(wǎng)絡(luò)異常*/
apiException.setCode(CodeException.HTTP_ERROR);
apiException.setDisplayMessage(HttpException_MSG);
} else if (e instanceof HttpTimeException) {
/*自定義運(yùn)行時(shí)異常*/
HttpTimeException exception = (HttpTimeException) e;
apiException.setCode(CodeException.RUNTIME_ERROR);
apiException.setDisplayMessage(exception.getMessage());
} else if (e instanceof ConnectException||e instanceof SocketTimeoutException) {
/*鏈接異常*/
apiException.setCode(CodeException.HTTP_ERROR);
apiException.setDisplayMessage(ConnectException_MSG);
} else if (e instanceof JSONPathException || e instanceof JSONException || e instanceof ParseException) {
/*fastjson解析異常*/
apiException.setCode(CodeException.JSON_ERROR);
apiException.setDisplayMessage(JSONException_MSG);
}else if (e instanceof UnknownHostException){
/*無法解析該域名異常*/
apiException.setCode(CodeException.UNKOWNHOST_ERROR);
apiException.setDisplayMessage(UnknownHostException_MSG);
} else {
/*未知異常*/
apiException.setCode(CodeException.UNKNOWN_ERROR);
apiException.setDisplayMessage(e.getMessage());
}
return apiException;
}
}
這個異常工廠類中的異常判斷在實(shí)際開發(fā)中疯坤,可以動態(tài)的自己添加报慕,可以將分類更加細(xì)化完善!
5.rx錯誤異常的轉(zhuǎn)換
rx在鏈接調(diào)用過程中產(chǎn)生的異常默認(rèn)是通過Subscriber的onError(Throwable e)方法回調(diào)压怠,這里我們需要將Throwable 轉(zhuǎn)換成自定義ApiException回調(diào),所以需要調(diào)用rxjava中的onErrorResumeNext方法眠冈,在異常回調(diào)前通過異常工廠類FactoryException處理返回統(tǒng)一的ApiException菌瘫。
偽代碼
****
******
********
Observable observable = basePar.getObservable(httpService)
/*失敗后的retry配置*/
.retryWhen(new RetryWhenNetworkException())
/*異常處理*/
.onErrorResumeNext(funcException)
**********
/**
* 異常處理
*/
Func1 funcException = new Func1<Throwable, Observable>() {
@Override
public Observable call(Throwable throwable) {
return Observable.error(FactoryException.analysisExcetpion(throwable));
}
};
6.回調(diào)結(jié)果的統(tǒng)一處理
- 1.因?yàn)楦臑榻y(tǒng)一的錯誤毀掉類型蜗顽,需要修改之前的回到接口類
/**
* 成功回調(diào)處理
* Created by WZG on 2016/7/16.
*/
public interface HttpOnNextListener {
/**
* 成功后回調(diào)方法
* @param resulte
* @param mothead
*/
void onNext(String resulte,String mothead);
/**
* 失敗
* 失敗或者錯誤方法
* 自定義異常處理
* @param e
*/
void onError(ApiException e);
}
- 2.onError(Throwable e)回調(diào)處理
/**
* 錯誤統(tǒng)一處理
*
* @param e
*/
private void errorDo(Throwable e) {
Context context = mActivity.get();
if (context == null) return;
HttpOnNextListener httpOnNextListener = mSubscriberOnNextListener.get();
if (httpOnNextListener == null) return;
if (e instanceof ApiException) {
httpOnNextListener.onError((ApiException) e);
} else if (e instanceof HttpTimeException) {
HttpTimeException exception=(HttpTimeException)e;
httpOnNextListener.onError(new ApiException(exception,CodeException.RUNTIME_ERROR,exception.getMessage()));
} else {
httpOnNextListener.onError(new ApiException(e, CodeException.UNKNOWN_ERROR,e.getMessage()));
}
/*可以在這里統(tǒng)一處理錯誤處理-可自由擴(kuò)展*/
Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
}
這里可以統(tǒng)一對異常進(jìn)行統(tǒng)一處理,默認(rèn)現(xiàn)在是toast提示雨让,當(dāng)然也有回調(diào)的傳遞
- 3.顯示界面
@Override
public void onNext(String resulte, String mothead) {
*****
}
@Override
public void onError(ApiException e) {
tvMsg.setText("失敼透恰:\ncode=" + e.getCode()+"\nmsg:"+e.getDisplayMessage());
}
最后統(tǒng)一回調(diào)在onError中傳遞回一個ApiException對象