Retrofit+RxJava网络请求异常处理

作者: Ruheng | 来源:发表于2017-01-23 17:03 被阅读8798次

    本文内容是基于Retrofit + RxJava做的一些巧妙的封装。主要讲解针对网络请求的错误信息进行一次封装,方便我们根据返回的状态合理地在UI界面进行显示。并结合上篇文章对Retrofit的配置。对RxJava+Retrofit网络请求使用进行的封装,包括缓存处理,请求异常处理等内容,使用大多数网络请求状况,即拽即用。可以去最下面的地址下载代码。

    本文内容是基于RxJava 2.0及Retrofit 2.1分析的。参考了Rxjava +Retrofit 你需要掌握的几个技巧,Retrofit缓存,统一对有无网络处理, 异常处理,返回结果问题
    下面列出具体添加的依赖。

     //引入okhttp
        compile 'com.squareup.okhttp3:okhttp:3.5.0'
        //引入retrofit
        compile 'com.squareup.retrofit2:retrofit:2.1.0'
        //引入rxjava
        compile 'io.reactivex.rxjava2:rxjava:2.0.4'
        //引入Log拦截器,方便DEBUG模式输出log信息
        compile 'com.squareup.okhttp3:logging-interceptor:3.5.0'
        //引入rxjava适配器,方便rxjava与retrofit的结合
        compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
        //引入json转换器,方便将返回的数据转换为json格式
        compile 'com.squareup.retrofit2:converter-gson:2.1.0'
        //引入rxandroid
        compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    

    异常处理的必要性

    以下这些错误,都是在网络请求中经常见的。我们可以通过Toast弹出消息通知用户具体的异常以及加载对应的UI界面。除此之外,通过具体的异常信息,方便我们及时的排查项目中的BUG。



    那么问题就来了,我们如何判断异常的类型?

    这就要从服务器返回的数据格式说起了。

    我们一般请求的返回都是像下面这样

    {
       "code":"200",
       "message":"Return Successd!",
       "data":{
             "name":"张三"
              "age":3
       }
    }
    

    服务器端返回数据约定俗称就是大概以上的格式。可能具体的code码表示的含义不一样,这个可以与服务器端人员交流,灵活变化。
    关于Retrofit的基本配置就不再讲述了,可以看我的另一篇文章。这里具体讲解如何对服务器返回数据封装以及使用RxJava对错误信息处理。

    封装返回数据及异常类型判断

    封装返回数据
    对于上述的服务器返回数据我们要对code做出一些判断,code不为200(假设200表示请求网络成功)就抛出异常。所以我们新建一个BaseResponse类,对应上面的数据结构。

    public class BaseResponse<T> {
    
        private int code;
        private String msg;
        private T data;
    //该方法假设服务器返回200表示成功返回结果,其他数字表示异常
        public boolean isOk() {
            return code ==200;
        }
    //省略getter,setter方法
    }
    

    这算是所有实体的一个基类,data可以为任何数据类型。

    然后要对返回结果进行预处理,新建一个ExceptionHandle。预处理无非就是当根据返回数据BaseResponse的isOk()方法判断为是否为true,若为true则正常处理,否则抛出异常让ExceptionHandle进一步处理,判断异常为何种异常。我们先跳过前面的逻辑,先了解如何判断是何种异常?
    判断异常类型

    public class ExceptionHandle {
        //该方法用来判断异常类型 并将异常类型封装在ResponeThrowable返回
        public static ResponeThrowable handleException(Throwable e) {
              if (e instanceof HttpException) {
                      HttpException httpException = (HttpException) e;
                      ex = new ResponeThrowable(e, ERROR.HTTP_ERROR);
                      ex.message = "网络错误";
                      return ex;
              }
             ...................
             ...................其他类型异常判断
             ...................
         }
    }
    

    详细可看源码,下面会贴出地址。
    通过ExceptionHandle.handleException(Throwable e) 即可返回一个异常,并携带具体异常类型信息。

    现在我们已经知道了如何判断是否产生以上以及如何判断异常类型。接下来需要解决地就是如何把异常传递给Observer的onError(Throwable e)去处理异常。

    异常传递

    在进行异常传递的过程中,第一步我们先要判断服务器返回的数据是否是异常,如果不是异常则返回data数据,如果是异常则抛出异常。这个时候就包含了一个数据转换的过程即把BaseResponse对象转换成data类型的对象,所以需要map()操作符。

    (Observable<T>) upstream.map(new HandleFuc<T>())
    

    其中HandleFuc实现了Function<BaseResponse<T>, T>接口

     public static class HandleFuc<T> implements Function<BaseResponse<T>, T> {
            @Override
            public T apply(BaseResponse<T> response) throws Exception {
                //response中code码不为200 出现错误
                if (!response.isOk())
                    //抛出异常,把状态码及状态描述信息传入
                    throw new RuntimeException(response.getCode() + "" + response.getMsg() != null ? response.getMsg() : "");
                return response.getData();
            }
        }
    

    如果不出现异常则不会走第二步。如果出现异常,则需要进行第二步,即对异常进行判断,然后将ExceptionHandle.handleException(Throwable e) 返回的异常传入onError()中处理。

    重点来了:当产生异常时,应该终止对onNext()方法的调用并调用onError()方法。如果不继续处理,仅通过以上步骤,虽然会调用onError()方法,但是没有对异常进行判断,并且没有取消onNext()方法。那么有没有一个好的方法,可以即取消onNext()方法,又能在其中实现异常判断的执行,并且会调用onError()方法?

    如此强大的RxJava自然有这样的方法了,onErrorResumeNext()就能实现这个要求。对于onErrorResumeNext(),可以简单理解为:当发生错误的时候,由另外一个Observable来代替当前的Observable并继续发射数据。

    onErrorResumeNext()中传入的参数可以是一个Function接口。这样,我们可以在Function中生成一个Observable,该Observable执行异常判断的逻辑,并调用onError()方法。
    具体实现如下:

    (Observable<T>) upstream.map(new HandleFuc<T>()).onErrorResumeNext(new HttpResponseFunc<T>());
    
    public static class HttpResponseFunc<T> implements Function<Throwable, Observable<T>> {
            @Override
            public Observable<T> apply(Throwable throwable) throws Exception {
                return Observable.error(ExceptionHandle.handleException(throwable));
            }
        }
    

    至此,我们便实现了异常判断与传递的逻辑。这样我们就可以在onError()方法中提取具体的异常状态信息,进行相应的处理。
    大概流程是:map()进行数据类型转换,并检测异常。如果正常,返回data类型的数据。如果不正常,onErrorResumeNext()判断异常类型并传递异常
    下面展示一个简单的效果图:


    上述情况关闭了网络。当发起网络请求,没有网络则抛出异常,然后检测出具体异常,Toast提示异常类型,用户便知道是什么地方出错了。

    结合上篇文章对Retrofit的配置。对RxJava+Retrofit网络请求使用进行的封装,包括缓存处理,请求异常处理等内容,使用大多数网络请求状况,即拽即用。可以去下面的地址下载代码。
    代码地址

    相关文章

      网友评论

      • 6d6e8cb478b4:09-18 15:34:57.493 5109-5109/com.shop.gmshop W/System.err: retrofit2.adapter.rxjava.HttpException: HTTP 400 Bad Request
        09-18 15:34:57.493 5109-5109/com.shop.gmshop W/System.err: at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$SimpleCallAdapter$1.call(RxJavaCallAdapterFactory.java:163)
        09-18 15:34:57.494 5109-5109/com.shop.gmshop W/System.err: at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$SimpleCallAdapter$1.call(RxJavaCallAdapterFactory.java:158)
        09-18 15:34:57.494 5109-5109/com.shop.gmshop W/System.err: at rx.internal.operators.OperatorMap$1.onNext(OperatorMap.java:54)
        09-18 15:34:57.494 5109-5109/com.shop.gmshop W/System.err: at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:113)
      • 6d6e8cb478b4: 这种错误通常是什么原因呢?
      • wing_zhong:...你第一个处理数据用map的时候返回的异常都 是runtime,第二个异常判断就没用了啊,上面传来的一定是RuntimeException
      • 1d04b0e74ec1:如果数据中的data是一个数组该怎么解析
      • 8070869b33b7:流星直播是你做的吗
        Ruheng: @别这样嘛 不是,网上找的截图。借来用的

      本文标题:Retrofit+RxJava网络请求异常处理

      本文链接:https://www.haomeiwen.com/subject/plyabttx.html