Retrofit请求数据对错误以及网络异常的处理
Posted 一叶飘舟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Retrofit请求数据对错误以及网络异常的处理相关的知识,希望对你有一定的参考价值。
异常处理
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 + ")";
}
}
转自:http://blog.csdn.net/efan006/article/details/50544204
补充:Retrofit+RxJava 优雅的处理服务器返回异常、错误
以上是关于Retrofit请求数据对错误以及网络异常的处理的主要内容,如果未能解决你的问题,请参考以下文章
Android Retrofit+RxJava 优雅的处理服务器返回异常错误