背景
在前面Rxjava+ReTrofit+okHttp深入淺出-終極封裝專欄我們已經全面的封裝了一套可以投入實戰的框架,最近QQ
群中有兄弟說異常處理這塊可以優化優化並給出了建議參考專案,果斷重新將之前的封裝完善走起來,將請求過程中的處理統一封裝起來,回撥給呼叫者,根據自定義回撥型別方便查詢錯誤型別和資訊。
前提
本章的內容基於掌握了前面封裝的原理以後,學期起來才能完全的理解
效果:
通過統一的異常處理,可以實現各種異常的統一處理,然後通過統一回撥給使用者,方便統一展示和顯示提示給使用者
第一條錯誤:故意修改了
service
裡面方法地址,導致錯誤第二條錯誤:過期
token
,伺服器返回的錯誤資訊
優化之路
1.定義回撥異常類
定義的回撥類,方便回撥介面統一處理,其中包含錯誤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.定義錯誤碼
自定義錯誤碼,相關的錯誤碼可以自行設定規則,框架現在給出了常用的錯誤碼定義,採用上一章講解的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解析異常
3.完善自定義執行時異常
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
碼和對應的錯誤資訊
4.建立異常工廠類
異常工廠類中,通過傳入對應的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;
}
}複製程式碼
這個異常工廠類中的異常判斷在實際開發中,可以動態的自己新增,可以將分類更加細化完善!
5.rx錯誤異常的轉換
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));
}
};複製程式碼
6.回撥結果的統一處理
- 1.因為改為統一的錯誤毀掉型別,需要修改之前的回到介面類
/**
* 成功回撥處理
* 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);
}複製程式碼
- 2.
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
提示,當然也有回撥的傳遞
- 3.顯示介面
@Override
public void onNext(String resulte, String mothead) {
*****
}
@Override
public void onError(ApiException e) {
tvMsg.setText("失敗:\ncode=" + e.getCode()+"\nmsg:"+e.getDisplayMessage());
}複製程式碼
最後統一回撥在onError
中傳遞迴一個ApiException
物件