博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
RxRetrofit - 终极封装 - 深入浅出 & 异常
阅读量:6267 次
发布时间:2019-06-22

本文共 7012 字,大约阅读时间需要 23 分钟。

背景

在前面我们已经全面的封装了一套可以投入实战的框架,最近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.定义错误码

自定义错误码,相关的错误码可以自行设定规则,框架现在给出了常用的错误码定义,采用上一章讲解的来定义错误码的使用:

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 {    }}复制代码

因为是在基础上完善的异常处理,这里解析使用的是 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
() { @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对象


终极封装专栏


项目地址


建议

转载地址:http://bwcpa.baihongyu.com/

你可能感兴趣的文章
Java面向对象的三个特征与含义
查看>>
tkinter 创建登陆注册界面
查看>>
linux常用命令
查看>>
决策树-流水线
查看>>
linux系统被黑客入侵排查思路
查看>>
个人中心标签页导航
查看>>
如何刻录XP系统盘
查看>>
nios II--实验4——按键中断硬件部分
查看>>
pycharm多行批量缩进和反向缩进快捷键
查看>>
设计模式——外观模式(Facade)
查看>>
Sublime Text 2 使用心得
查看>>
SQLite数据库查询优化
查看>>
UIViewController各个方法的加载顺序
查看>>
Jenkins新建节点,启动方式没有“通过Java Web启动代理”选项怎么办?
查看>>
iOS html格式解析
查看>>
软件工程实践2017第一次作业
查看>>
Homestead 中使用 laravel-mix 问题汇总
查看>>
Selenium2Library系列 keywords 之 _SelectElementKeywords 之 unselect_from_list(self, locator, *items)...
查看>>
GNU/Linux 初学之旅(转)
查看>>
【java】Split函数踩坑记
查看>>