一、杂谈

前一阵子博客备案因为名字问题被驳回了两次也是够了,现在在公司里一直写业务代码,这让本来就不会的算法的我算法水平更加烂,最近在跟着优酷上的一个小姐姐学魔方,智商跟不太上了啊哈哈哈哈哈。OK,步入正题,名字叫Retrofit异常处理,可是内容应该主要是针对网络的统一异常处理,我之前的异常处理都是在BaseActivity或者是BaseFragment中去添加一个方法,然后在网络请求有问题时去调用这个方法,但是后来我把我用频率较多的代码(包括Base)打包发布了一个仓库AndroidQuick,这样的话我的异常处理就没法在Base层里面处理了,而且本身的处理方式就有很多不完善的地方。

二、BaseResponse(Response基类)

在BaseResponse中判断请求有无错误(判断与后台约定的code等),如果不正确,带着code调用NetworkError网络统一异常处理类

  1. 接口示例
  1. @FormUrlEncoded
  2. @POST(Constants.BASE_API + "sendCode")
  3. Flowable<BaseResponse<SendCodeBean>> getMobileCode(@FieldMap Map<String, String> values);
  1. BaseResponse
  1. public class BaseResponse<T> {
  2. private int code;
  3. private String msg;
  4. private T res;
  5. /**
  6. * 这个方法时已经成功访问后台了,code是后台约定的错误码,判断访问是否成功
  7. *
  8. * @param context 在做异常处理的时候可能涉及到跳转Activity
  9. * @return 返回成功或失败
  10. */
  11. public boolean isOk(Context context) {
  12. if (code == 200) {
  13. return true;
  14. } else {
  15. NetworkError.error(context, new ServerException(code, msg));
  16. return false;
  17. }
  18. }
  19. // get/set方法...
  20. }

三、NetworkError(网络统一异常处理类)

  • 不太会写文章,我在代码里做了详细注释。

  • 代码

  1. public class NetworkError {
  2. /**
  3. * @param context 可以用于跳转Activity等操作
  4. */
  5. public static void error(Context context, Throwable throwable) {
  6. RetrofitException.ResponeThrowable responeThrowable = RetrofitException.retrofitException(throwable);
  7. // 此处可以通过判断错误代码来实现根据不同的错误代码做出相应的反应
  8. switch (responeThrowable.code) {
  9. case RetrofitException.ERROR.UNKNOWN:
  10. case RetrofitException.ERROR.PARSE_ERROR:
  11. case RetrofitException.ERROR.NETWORD_ERROR:
  12. case RetrofitException.ERROR.HTTP_ERROR:
  13. case RetrofitException.ERROR.SSL_ERROR:
  14. Toast.makeText(context, responeThrowable.message, Toast.LENGTH_SHORT).show();
  15. break;
  16. case -1:
  17. // 跳转到登陆页面
  18. context.startActivity(new Intent(context, LoginActivity.class));
  19. // 结束除LoginActivity之外的所有Activity
  20. AppManager.finishAllActivity(LoginActivity.class);
  21. break;
  22. default:
  23. Toast.makeText(context, responeThrowable.message, Toast.LENGTH_SHORT).show();
  24. break;
  25. }
  26. }
  27. }

四、ServerException(服务器下发的异常)

  1. public class ServerException extends RuntimeException {
  2. public int code;
  3. public ServerException(int code, String message) {
  4. super(message);
  5. this.code = code;
  6. }
  7. }

五、RetrofitException(网络异常类)

  • 这个类主要是通过instanceof操作符来判断异常的类型

  • 代码

  1. public class RetrofitException {
  2. private static final int UNAUTHORIZED = 401;
  3. private static final int FORBIDDEN = 403;
  4. private static final int NOT_FOUND = 404;
  5. private static final int REQUEST_TIMEOUT = 408;
  6. private static final int INTERNAL_SERVER_ERROR = 500;
  7. private static final int BAD_GATEWAY = 502;
  8. private static final int SERVICE_UNAVAILABLE = 503;
  9. private static final int GATEWAY_TIMEOUT = 504;
  10. public static ResponeThrowable retrofitException(Throwable e) {
  11. ResponeThrowable ex;
  12. if (e instanceof HttpException) {
  13. HttpException httpException = (HttpException) e;
  14. ex = new ResponeThrowable(e, ERROR.HTTP_ERROR);
  15. switch (httpException.code()) {
  16. case UNAUTHORIZED:
  17. case FORBIDDEN:
  18. case NOT_FOUND:
  19. case REQUEST_TIMEOUT:
  20. case GATEWAY_TIMEOUT:
  21. case INTERNAL_SERVER_ERROR:
  22. case BAD_GATEWAY:
  23. case SERVICE_UNAVAILABLE:
  24. default:
  25. ex.message = "网络错误";
  26. break;
  27. }
  28. return ex;
  29. } else if (e instanceof ServerException) {
  30. // 服务器下发的错误
  31. ServerException resultException = (ServerException) e;
  32. ex = new ResponeThrowable(resultException, resultException.code);
  33. ex.message = resultException.getMessage();
  34. return ex;
  35. } else if (e instanceof JsonParseException
  36. || e instanceof JSONException
  37. || e instanceof ParseException) {
  38. ex = new ResponeThrowable(e, ERROR.PARSE_ERROR);
  39. ex.message = "解析错误";
  40. return ex;
  41. } else if (e instanceof ConnectException
  42. || e instanceof SocketTimeoutException
  43. || e instanceof UnknownHostException) {
  44. ex = new ResponeThrowable(e, ERROR.NETWORD_ERROR);
  45. ex.message = "连接失败";
  46. return ex;
  47. } else if (e instanceof SSLHandshakeException) {
  48. ex = new ResponeThrowable(e, ERROR.SSL_ERROR);
  49. ex.message = "证书验证失败";
  50. return ex;
  51. } else {
  52. ex = new ResponeThrowable(e, ERROR.UNKNOWN);
  53. ex.message = "未知错误";
  54. return ex;
  55. }
  56. }
  57. /**
  58. * 约定异常
  59. */
  60. class ERROR {
  61. /**
  62. * 未知错误
  63. */
  64. public static final int UNKNOWN = 1000;
  65. /**
  66. * 解析错误
  67. */
  68. public static final int PARSE_ERROR = 1001;
  69. /**
  70. * 网络错误
  71. */
  72. public static final int NETWORD_ERROR = 1002;
  73. /**
  74. * 协议出错
  75. */
  76. public static final int HTTP_ERROR = 1003;
  77. /**
  78. * 证书出错
  79. */
  80. public static final int SSL_ERROR = 1005;
  81. }
  82. public static class ResponeThrowable extends Exception {
  83. public int code;
  84. public String message;
  85. public ResponeThrowable(Throwable throwable, int code) {
  86. super(throwable);
  87. this.code = code;
  88. }
  89. }
  90. }

六、使用方式

  1. Map<String, String> map = new LinkedHashMap<>();
  2. map.put("id", mId);
  3. map.put("uid", SPUtils.getInstance().getString("uid"));
  4. RetrofitClient
  5. // 单例调用
  6. .getInstance()
  7. // 获取请求接口
  8. .gService
  9. // 调用接口方法
  10. .getMobileCode(map)
  11. // 通过compose切换线程
  12. .compose(RxUtil.rxSchedulerHelper())
  13. // 订阅
  14. .subscribe(response -> {
  15. if (response.isOk(mContext)) {
  16. // 全部正确
  17. } else {
  18. // 服务器下发的错误(BaseResponse的isOk()会调用异常处理方法)
  19. }
  20. }, throwable -> {
  21. LogUtils.e(throwable);
  22. // Retrofit异常
  23. NetworkError.error(context, throwable);
  24. });

七、源码

https://github.com/sdwfqin/AndroidQuick

欢迎提供您宝贵的意见与建议,E-mail:zhangqin@sdwfqin.com