在前面Rxjava+ReTrofit+okHttp深刻淺出-終極封裝專欄咱們已經全面的封裝了一套能夠投入實戰的框架,最近QQ
羣中有兄弟說異常處理這塊能夠優化優化並給出了建議參考項目,果斷從新將以前的封裝完善走起來,將請求過程當中的處理統一封裝起來,回調給調用者,根據自定義回調類型方便查詢錯誤類型和信息。html
本章的內容基於掌握了前面封裝的原理之後,學期起來才能徹底的理解java
經過統一的異常處理,能夠實現各類異常的統一處理,而後經過統一回調給使用者,方便統一展現和顯示提示給用戶github
第一條錯誤:故意修改了service
裏面方法地址,致使錯誤json
第二條錯誤:過時token
,服務器返回的錯誤信息api
定義的回調類,方便回調接口統一處理,其中包含錯誤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;
}
}複製代碼
自定義錯誤碼,相關的錯誤碼能夠自行設定規則,框架如今給出了經常使用的錯誤碼定義,採用上一章講解的Android註解方式來定義錯誤碼的使用:服務器
public class CodeException {
/*網絡錯誤*/
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;
/*運行時異常-包含自定義異常*/
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 {
}
}複製代碼
由於是在Rxjava+ReTrofit+okHttp深刻淺出-終極封裝六特殊篇(變種String替換Gson自由擴展)基礎上完善的異常處理,這裏解析使用的是 fastjson的異常定義json解析異常網絡
HttpTimeException
類在以前的封裝中就已經存在,經過它在處理服務器返回錯誤信息和緩存錯誤信息,因此咱們只是完善它的調用規則,讓它更加合理框架
public class HttpTimeException extends RuntimeException {
/*未知錯誤*/
public static final int UNKOWN_ERROR = 0x1002;
/*本地無緩存錯誤*/
public static final int NO_CHACHE_ERROR = 0x1003;
/*緩存過期錯誤*/
public static final int CHACHE_TIMEOUT_ERROR = 0x1004;
public HttpTimeException(int resultCode) {
this(getApiExceptionMessage(resultCode));
}
public HttpTimeException(String detailMessage) {
super(detailMessage);
}
/** * 轉換錯誤數據 * * @param code * @return */
private static String getApiExceptionMessage(int code) {
switch (code) {
case UNKOWN_ERROR:
return "錯誤:網絡錯誤";
case NO_CHACHE_ERROR:
return "錯誤:無緩存數據";
case CHACHE_TIMEOUT_ERROR:
return "錯誤:緩存數據過時";
default:
return "錯誤:未知錯誤";
}
}
}複製代碼
完善後:加入code
碼和對應的錯誤信息
異常工廠類中,經過傳入對應的Throwable
錯誤,而後根據Throwable
的不一樣類型,生成不一樣的與之對應的ApiException
異常,最後將ApiException
異常返回給最後的rx回調onerror
方法,最後onerror
方法統一對異常進行處理(若是你的需求又這樣的要求)回調給用戶界面;
public class FactoryException {
private static final String HttpException_MSG = "網絡錯誤";
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) {
/*網絡異常*/
apiException.setCode(CodeException.HTTP_ERROR);
apiException.setDisplayMessage(HttpException_MSG);
} else if (e instanceof HttpTimeException) {
/*自定義運行時異常*/
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;
}
}複製代碼
這個異常工廠類中的異常判斷在實際開發中,能夠動態的本身添加,能夠將分類更加細化完善!
rx在連接調用過程當中產生的異常默認是經過Subscriber的onError(Throwable e)
方法回調,這裏咱們須要將Throwable
轉換成自定義ApiException
回調,因此須要調用rxjava中的onErrorResumeNext
方法,在異常回調前經過異常工廠類FactoryException
處理返回統一的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));
}
};複製代碼
/** * 成功回調處理 * Created by WZG on 2016/7/16. */
public interface HttpOnNextListener {
/** * 成功後回調方法 * @param resulte * @param mothead */
void onNext(String resulte,String mothead);
/** * 失敗 * 失敗或者錯誤方法 * 自定義異常處理 * @param e */
void onError(ApiException e);
}複製代碼
onError(Throwable e)
回調處理/** * 錯誤統一處理 * * @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()));
}
/*能夠在這裏統一處理錯誤處理-可自由擴展*/
Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
}複製代碼
這裏能夠統一對異常進行統一處理,默認如今是toast
提示,固然也有回調的傳遞
@Override
public void onNext(String resulte, String mothead) {
*****
}
@Override
public void onError(ApiException e) {
tvMsg.setText("失敗:\ncode=" + e.getCode()+"\nmsg:"+e.getDisplayMessage());
}複製代碼
最後統一回調在onError
中傳遞迴一個ApiException
對象