Retrofit+RxJava实战日志(3)-网络异常处理

来源:互联网 发布:网络专升本 编辑:程序博客网 时间:2024/05/01 01:54

上一篇文章写了Retrofit和RxJava的基本使用,最后的subscriber并没有写具体实现
成功的返回通常对应了各种不同的处理,而异常返回通常有着统一的处理
因此这一篇单独讲讲异常处理

Retrofit本身会抛出HttpException,Gson解析会抛出解析异常,
此外我们还应该处理与服务器约定好的“异常”,即上一篇提到的返回数据中result字段值不会0的情况

这里要先解决一个问题,就是Gson构建的对象,通过注解定义key名,以变量的类型定value的类型,
但如果同样的key在不同情况下属于不同的数据类型,就会出问题。
比如上一篇文章提及,服务器返回格式是

{    "result":"结果代号,0表示成功",    "msg":"成功返回时是消息数据列表,失败时是异常消息文本"}

那么msg究竟应该定义为String,还是一个List呢

我找到的解决方法就是:
注册一个自定义的转换类GsonResponseBodyConverter
先用一个只含result变量的Model类去解析获得result值
如果失败,则用msg是String的Model类再去解析msg值,然后组成一个ResultException
如果成功,则按照原本的Model类解析
代码如下:

class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {    private final Gson gson;    private final Type type;    GsonResponseBodyConverter(Gson gson, Type type) {        this.gson = gson;        this.type = type;    }    @Override    public T convert(ResponseBody value) throws IOException{        String response = value.string();        try {            Log.d("Network", "response>>" + response);            //ResultResponse 只解析result字段            ResultResponse resultResponse = gson.fromJson(response, ResultResponse.class);            if (resultResponse.getResult() == 0){                //result==0表示成功返回,继续用本来的Model类解析                return gson.fromJson(response, type);            } else {                //ErrResponse 将msg解析为异常消息文本                ErrResponse errResponse = gson.fromJson(response, ErrResponse.class);                throw new ResultException(resultResponse.getResult(), errResponse.getMsg());            }        } finally {        }    }}

这个类用于捕获服务器约定的错误类型

public class ResultException extends RuntimeException {    private int errCode = 0;    public ResultException(int errCode, String msg) {        super(msg);        this.errCode = errCode;    }    public int getErrCode() {        return errCode;    }}

拷贝原生的ResponseConverterFactory,将GsonResponseBodyConverter替换为前面我们自定义的

public class ResponseConverterFactory extends Converter.Factory {    ...    ...    @Override    public Converter<ResponseBody, ?> fromResponseBody(Type type, Annotation[] annotations) {        return new GsonResponseBodyConverter<>(gson, type);    }    @Override    public Converter<?, RequestBody> toRequestBody(Type type, Annotation[] annotations) {        return new GsonRequestBodyConverter<>(gson, type);    }}

然后在构建Retrofit时注册这个工厂类

Retrofit = new Retrofit.Builder()                .baseUrl(API_SERVER + "/")                //注册自定义的工厂类                .addConverterFactory(ResponseConverterFactory.create())                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())                .client(mOkHttpClient)                .build();

这样就完成了Retrofit也可以抛出服务器约定异常

然后就是具体的处理:

public abstract class AbsAPICallback<T> extends Subscriber<T> {    //对应HTTP的状态码    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;    //出错提示    private final String networkMsg;    private final String parseMsg;    private final String unknownMsg;    protected AbsAPICallback(String networkMsg, String parseMsg, String unknownMsg) {        this.networkMsg = networkMsg;        this.parseMsg = parseMsg;        this.unknownMsg = unknownMsg;    }    @Override    public void onError(Throwable e) {        Throwable throwable = e;        //获取最根源的异常        while(throwable.getCause() != null){            e = throwable;            throwable = throwable.getCause();        }        ApiException ex;        if (e instanceof HttpException){             //HTTP错误            HttpException httpException = (HttpException) e;            ex = new ApiException(e, httpException.code());            switch(httpException.code()){                case UNAUTHORIZED:                case FORBIDDEN:                    onPermissionError(ex);          //权限错误,需要实现                    break;                case NOT_FOUND:                case REQUEST_TIMEOUT:                case GATEWAY_TIMEOUT:                case INTERNAL_SERVER_ERROR:                case BAD_GATEWAY:                case SERVICE_UNAVAILABLE:                default:                    ex.setDisplayMessage(networkMsg);  //均视为网络错误                    onError(ex);                    break;            }        } else if (e instanceof ResultException){    //服务器返回的错误            ResultException resultException = (ResultException) e;            ex = new ApiException(resultException, resultException.getErrCode());                           onResultError(ex);          } else if (e instanceof JsonParseException                || e instanceof JSONException                || e instanceof ParseException){            ex = new ApiException(e, ApiException.PARSE_ERROR);            ex.setDisplayMessage(parseMsg);            //均视为解析错误            onError(ex);        } else {            ex = new ApiException(e, ApiException.UNKNOWN);            ex.setDisplayMessage(unknownMsg);          //未知错误            onError(ex);        }    }    /**     * 错误回调     */    protected abstract void onError(ApiException ex);    /**     * 权限错误,需要实现重新登录操作     */    protected abstract void onPermissionError(ApiException ex);    /**     * 服务器返回的错误     */    protected abstract void onResultError(ApiException ex);    @Override    public void onCompleted() {    }}

自定义ApiException,携带了异常代码和信息,以及根源Throwable,足够调用者需要

public class ApiException extends Exception {    private final int code;    private String displayMessage;    public static final int UNKNOWN = 1000;    public static final int PARSE_ERROR = 1001;    public ApiException(Throwable throwable, int code) {        super(throwable);        this.code = code;    }    public int getCode() {        return code;    }    public String getDisplayMessage() {        return displayMessage;    }    public void setDisplayMessage(String msg) {        this.displayMessage = msg + "(code:" + code + ")";    }}
1 0
原创粉丝点击