背景
在前面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
对象