Retrofit本身会抛出HttpException,Gson解析会抛出解析异常, 此外我们还应该处理与服务器约定好的“异常”,即上一篇提到的返回数据中result字段值不会0的情况
这里要先解决一个问题,就是Gson构建的对象,通过注解定义key名,以变量的类型定value的类型, 但如果同样的key在不同情况下属于不同的数据类型,就会出问题。
假如服务器返回格式是
{ "result":"结果代号,0表示成功", "msg":"成功返回时是消息数据列表,失败时是异常消息文本" } 1234 1234么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 { } } } 12345678910111213141516171819202122232425262728 12345678910111213141516171819202122232425262728这个类用于捕获服务器约定的错误类型
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; } } 12345678910111213 12345678910111213拷贝原生的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); } } 12345678910111213141516 12345678910111213141516然后在构建Retrofit时注册这个工厂类
Retrofit = new Retrofit.Builder() .baseUrl(API_SERVER + "/") //注册自定义的工厂类 .addConverterFactory(ResponseConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .client(mOkHttpClient) .build(); 1234567 1234567这样就完成了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() { } } 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091自定义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 + ")"; } } 1234567891011121314151617181920212223 1234567891011121314151617181920212223转自:http://blog.csdn.net/efan006/article/details/50544204
补充:Retrofit+RxJava 优雅的处理服务器返回异常、错误
(function () {('pre.prettyprint code').each(function () { var lines = (this).text().split(′\n′).length;var numbering = $(' ').addClass('pre-numbering').hide(); (this).addClass(′has−numbering′).parent().append( numbering); for (i = 1; i