背景
在前面Rxjava+ReTrofit+okHttp深入浅出-终极封装专栏我们已经全面的封装了一套可以投入实战的框架,最近开设了微信群中有兄弟说异常处理这块可以优化优化并给出了建议参考项目,果断重新将之前的封装完善走起来,将请求过程中的处理统一封装起来,回调给调用者,根据自定义回调类型方便查询错误类型和信息。
前提
本章的内容基于掌握了前面封装的原理以后,学期起来才能完全的理解
RxJava+Retrofit+OkHttp深入浅出-终极封装专栏
效果:
20161213112322273.gif通过统一的异常处理,可以实现各种异常的统一处理,然后通过统一回调给使用者,方便统一展示和显示提示给用户
-
第一条错误:故意修改了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对象
网友评论