Android RxJava+Retrofit网络异常、状态码统一处理

来源:互联网 发布:网络交友的危害翻译 编辑:程序博客网 时间:2024/05/21 16:58

Android RxJava+Retrofit 网络异常捕获、状态码统一处理

前言

近来使用RxJava+Retrofit进行开发,在项目中遇到这样一个需求,联网请求获得数据异常时,需要将对应的Message和StatusCode进行获得并展示,比如:
1.服务器连接Error: 对应的返回404,500等等;
2.没有网络状态(没有4g,3g,是否处于wifi环境下等);

参考文章:
Rxjava +Retrofit 你需要掌握的几个技巧,Retrofit缓存,RxJava封装,统一对有无网络处理,异常处理, 返回结果问题 @码小白

一、简单的获取处理

最简单的处理方式,直接对返回的throwable进行类型判断处理:

//先判断网络环境if(!NetUtils.is4G(context)){    return;}//再联网请求,对throwable进行判断ServiceHelper.getInstance()          .getModelResult(param1, param2)          .subscribeOn(Schedulers.io())          .observeOn(AndroidSchedulers.mainThread())          .subscribe(new Subscriber<Model>() {                 @Override                  public void onCompleted() {                  }                  @Override                  public void onError(Throwable e) {                      if(e instanceof HttpException){                          //获取对应statusCode和Message                          HttpException exception = (HttpException)e;                          String message = exception.response().message();                          int code = exception.response().code();                      }else if(e instanceof SSLHandshakeException){                        //接下来就是各种异常类型判断...                      }else if(e instanceof ...){                      }...                       ...                  }                  @Override                  public void onNext(Model model) {                  }          });

显然,代码并不难以理解,但是非常麻烦,总不至于每次都要进行这样的大块代码复制粘贴吧。
请注意,进行类型判断的的HttpException为

import retrofit2.adapter.rxjava.HttpException;

所以需要我们依赖:

compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

二、NetErrorUtil封装

1.首先我们创建一个Throwable的管理类

public class ExceptionHandle {    private static final int UNAUTHORIZED = 401;    private static final int FORBIDDEN = 403;    private static final int NOT_FOUND = 404;    private static final int REQUEST_TIMEOUT = 408;    private static final int INTERNAL_SERVER_ERROR = 500;    private static final int BAD_GATEWAY = 502;    private static final int SERVICE_UNAVAILABLE = 503;    private static final int GATEWAY_TIMEOUT = 504;    public static ResponeThrowable handleException(Throwable e) {        ResponeThrowable ex;        Log.i("tag", "e.toString = " + e.toString());        if (e instanceof HttpException) {            HttpException httpException = (HttpException) e;            ex = new ResponeThrowable(e, ERROR.HTTP_ERROR);            switch (httpException.code()) {                case UNAUTHORIZED:                case FORBIDDEN:                case NOT_FOUND:                case REQUEST_TIMEOUT:                case GATEWAY_TIMEOUT:                case INTERNAL_SERVER_ERROR:                case BAD_GATEWAY:                case SERVICE_UNAVAILABLE:                default:                    //ex.code = httpException.code();                    ex.message = "网络错误";                    break;            }            return ex;        } else if (e instanceof ServerException) {            ServerException resultException = (ServerException) e;            ex = new ResponeThrowable(resultException, resultException.code);            ex.message = resultException.message;            return ex;        } else if (e instanceof JsonParseException                || e instanceof JSONException                /*|| e instanceof ParseException*/) {            ex = new ResponeThrowable(e, ERROR.PARSE_ERROR);            ex.message = "解析错误";            return ex;        } else if (e instanceof ConnectException) {            ex = new ResponeThrowable(e, ERROR.NETWORD_ERROR);            ex.message = "连接失败";            return ex;        } else if (e instanceof javax.net.ssl.SSLHandshakeException) {            ex = new ResponeThrowable(e, ERROR.SSL_ERROR);            ex.message = "证书验证失败";            return ex;        } else {            ex = new ResponeThrowable(e, ERROR.UNKNOWN);            ex.message = "未知错误";            return ex;        }    }    /**     * 约定异常     */    class ERROR {        /**         * 未知错误         */        public static final int UNKNOWN = 1000;        /**         * 解析错误         */        public static final int PARSE_ERROR = 1001;        /**         * 网络错误         */        public static final int NETWORD_ERROR = 1002;        /**         * 协议出错         */        public static final int HTTP_ERROR = 1003;        /**         * 证书出错         */        public static final int SSL_ERROR = 1005;    }    public static class ResponeThrowable extends Exception {        public int code;        public String message;        public ResponeThrowable(Throwable throwable, int code) {            super(throwable);            this.code = code;        }    }    /**     * ServerException发生后,将自动转换为ResponeThrowable返回     */    class ServerException extends RuntimeException {        int code;        String message;    }}

在这个类中,我们把throwable进行类型统一判断:
1.若为Exception,我们再进行判断,根据不同种类的Exception,转化为ResponeThrowable返回,并赋予不同的code和message;
2.若为RuntimeException,我们再转换为ResponeThrowable返回;

总而言之,我们把获取到的异常,通过handleException()方法,转化为统一的ResponeThrowable返回,这个对象包含code和message。

2.然后是创建一个新的Subscriber基类

/** * Subscriber基类,可以在这里处理client网络连接状况 * (比如没有wifi,没有4g,没有联网等) * Created by fcn-mq on 2017/4/19. */public abstract class MySubscriber<T> extends Subscriber<T> {    private Context context;    public MySubscriber(Context context) {        this.context = context;    }    @Override    public void onStart() {        super.onStart();        Log.i("tag","MySubscriber.onStart()");        //接下来可以检查网络连接等操作        if (!NetworkUtil.isNetworkAvailable(context)) {            Toast.makeText(context, "当前网络不可用,请检查网络情况", Toast.LENGTH_SHORT).show();            // 一定好主动调用下面这一句,取消本次Subscriber订阅            if (!isUnsubscribed()) {                unsubscribe();            }            return;        }    }    @Override    public void onError(Throwable e) {        Log.e("tag","MySubscriber.throwable ="+e.toString());        Log.e("tag","MySubscriber.throwable ="+e.getMessage());        if(e instanceof Exception){            //访问获得对应的Exception            onError(ExceptionHandle.handleException(e));        }else {            //将Throwable 和 未知错误的status code返回            onError(new ExceptionHandle.ResponeThrowable(e,ExceptionHandle.ERROR.UNKNOWN));        }    }    public abstract void onError(ExceptionHandle.ResponeThrowable responeThrowable);    @Override    public void onCompleted() {        Log.i("tag","MySubscriber.onComplete()");    }}

这个就好理解了,我们可以在基类中统一进行客户端网络环境的判断,或者当网络异常发生时,统一转换为
ResponeThrowable,在onError(ExceptionHandle.ResponeThrowable responeThrowable)中回调,这个abstract的回调方法需要我们自己实现。

3.代码中使用:

new Retrofit.Builder()            .baseUrl(ConstantsApi.BASE_DOUBAN)             .addConverterFactory(GsonConverterFactory.create())             .addCallAdapterFactory(RxJavaCallAdapterFactory.create())             .client(client)             .build()             .create(DoubanMovieService.class)//获得对应的service对象             .getModelResult(param1, param2)  //网络请求             .subscribeOn(Schedulers.io())             .observeOn(AndroidSchedulers.mainThread())             .subscribe(new MySubscriber<Model>(context) {                 @Override                 public void onNext(Model model) {                   ...                 }                 @Override                 public void onError(ExceptionHandle.ResponeThrowable throwable) {                     LogUtil.m("tag","throwable =" + throwable.toString());                     //接下来就可以根据状态码进行处理...                     int statusCode = throwable.code;                     switch (statusCode){                         case ExceptionHandle.ERROR.SSL_ERROR:                          break;                         case ExceptionHandle.ERROR.UNKNOWN:                          break;                         case ExceptionHandle.ERROR.PARSE_ERROR:                          break;                         case ExceptionHandle.ERROR.NETWORD_ERROR:                             break;                         case ExceptionHandle.ERROR.HTTP_ERROR:                       break;                     }                 }             });

最后是NetErrorUtil的源码地址:点我点我

【GitHub地址】https://github.com/ButQingMei/Samples.git

0 0