Retrofit 系列文章导读:

  • Android Retrofit 源码系列(一)~ 原理剖析
  • Android Retrofit 源码系列(二)~ 自定义 CallAdapter
  • Android Retrofit 源码系列(三)~ 整合 RxJava、Coroutine 分析
  • Android Retrofit 源码系列(四)~ 文件上传
  • Android Retrofit 源码系列(五)~ 设计模式分析

通过上一篇对 Retrofit2 源码的分析,我们知道 CallAdapter 在 Retrofit 中扮演者非常重要的角色。

今天我们就来看看如何自定义 CallAdapter,来统一封装对错误信息的处理。然后,我们将通过源码来分析自定义的 CallAdapter 的整个执行流程。

本文基于的 Retrofit2 的版本是 2.7.0

自定义 CallAdapter

在自定义 CallAdapter 之前,我们先搞清楚需要哪些角色,在 Retrofit 中 CallAdapter 是通过工厂类来创建的,所以我们需要定义一个 CallAdapter 的工厂类;

为了和已有的 Call 区分,我们还需要自定义自己的 MyCall 接口,意思就是如果接口函数的返回类型是 MyCall,才会使用的我们自定义的 CallAdapter;有了 MyCall 接口,那么就需要一个对应的实现类来统一处理请求的结果(成功和失败),然后将成功或失败给我们自定义的 Callback。

所以自定义 CallAdapter 达到统一封装错误信息的目的,主要如下几个类:

  • MyCallAdapterFactory
  • MyCallAdapter
  • MyCall
  • MyCallImpl
  • Callback
  • ApiException

Callback.java:

interface Callback {// 成功回调    fun onSuccess(data: T?)    // 失败回调    fun onError(error: ApiException)}

MyCall.java:

interface MyCall {// 取消请求    fun cancel()    // 发起请求    fun request(callback: Callback)    fun clone(): MyCall}

MyCallImpl.java:

private class MyCallImpl(private val call: Call, private val callbackExecutor: Executor?) : MyCall {    override fun cancel() {        call.cancel()    }        override fun request(callback: Callback) {        call.enqueue(object : retrofit2.Callback {            override fun onFailure(call: Call, t: Throwable) {                // 局部函数                fun processFailure() {                    // 通过 transformException 函数统一处理异常                    callback.onError(ExceptionHelper.transformException(t))                }                // 失败回调所执行的线程                if (callbackExecutor != null) {                    callbackExecutor.execute {                        processFailure()                    }                } else {                    processFailure()                }            }            override fun onResponse(call: Call, response: Response) {                // 局部函数                fun processResponse() {                    val code = response.code()                    if (code in 200..299) {                        callback.onSuccess(response.body())                    } else {                        callback.onError(ApiException("---", "$code ${response.message()}"))                    }                }                // 成功回调所执行的线程                if (callbackExecutor != null) {                    callbackExecutor.execute {                        processResponse()                    }                } else {                    processResponse()                }            }        })    }    override fun clone(): MyCall {        return MyCallImpl(call.clone(), callbackExecutor)    }}

MyCallAdapter.java:

private class MyCallAdapter(private val responseType: Type, private val executor: Executor?) : CallAdapter> {    // 通过适配器模式将 Call 装成我们要的 MyCall    override fun adapt(call: Call): MyCall {        return MyCallImpl(call, executor)    }    override fun responseType(): Type {        return responseType    }}

MyCallAdapterFactory.java:

class MyCallAdapterFactory : CallAdapter.Factory() {    override fun get(returnType: Type, annotations: Array, retrofit: Retrofit): CallAdapter<*, *>? {                // 如果接口函数的返回类型不是 MyCall,则不使用 MyCallAdapter        if (getRawType(returnType) != MyCall::class.java) return null        // 返回类型的泛型校验        check(returnType is ParameterizedType) { "MyCall must have generic type (e.g., MyCall)" }        val responseType = getParameterUpperBound(0, returnType)        // 实际上是 MainThreadExecutor        val executor = retrofit.callbackExecutor()// 返回我们自定义的 MyCallAdapter        return MyCallAdapter(responseType, executor)    }}

自定义的异常类 ApiException.java

class ApiException(val errorCode: String?, errorMessage: String?) : Exception(errorMessage)

对异常统一处理,封装成我们自定义的异常 ApiException

class ExceptionHelper {    companion object {        private const val ERROR_CODE = "error_code_001"        @JvmStatic        fun transformException(t: Throwable): ApiException {            t.printStackTrace()            return when (t) {                is SocketTimeoutException -> ApiException(                    ERROR_CODE,                    "网络访问超时"                )                is ConnectException -> ApiException(                    ERROR_CODE,                    "网络连接异常"                )                is UnknownHostException -> ApiException(                    ERROR_CODE,                    "网络访问超时"                )                is JsonParseException -> ApiException(                    ERROR_CODE,                    "数据解析异常"                )                else -> ApiException(                    ERROR_CODE,                    t.message                )            }        }    }}

然后把我们自定义的 MyCallAdapterFactory 应用到 Retrofit 当中去:

val retrofit: Retrofit = Retrofit.Builder()    .baseUrl(API_URL)    // 添加 MyCallAdapterFactory 工厂    .addCallAdapterFactory(MyCallAdapterFactory())    .addConverterFactory(GsonConverterFactory.create())    .build()

最后,定义业务接口函数的返回 MyCall 类型:

interface UserService {    @POST("register")    @FormUrlEncoded    fun register2(        @Field("username") username: String,        @Field("mobile") mobile: String    ): MyCall>}private fun customCall() {    // MyCall    val call = userService.register2("chiclaim", "110")    call.request(object : Callback> {        override fun onSuccess(data: ResponseModel?) {            // todo something...        }        override fun onError(error: ApiException) {            // todo something...        }    })}

至此,我们就完成了通过自定义 CallAdapter 来统一封装对网络错误的处理。

源码解读 CallAdapter

在上一篇文章中《Android Retrofit 源码系列(一)~ 原理剖析》 我们也讲到了 CallAdapter,但是没有重点去分析 CallAdapter。

既然我们是通过 addCallAdapterFactory 函数来添加我们自定义的 CallAdapterFactory 的,那么我们看看里面是怎么实现的:

public Builder addCallAdapterFactory(CallAdapter.Factory factory) {  callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null"));  return this;}

其实就是将其放进一个集合而已,那什么时候使用到了呢?

如果记得上一篇对 Retrofit 执行流程分析有印象的话,我们应该知道 Retrofit 执行流程为:

Proxy.newProxyInstance()    -> InvocationHandler.invoke()        -> loadServiceMethod()            -> ServiceMethod.parseAnnotations()                -> HttpServiceMethod.parseAnnotations()

callAdapterFactories 是在 HttpServiceMethod.parseAnnotations 函数中使用到了:

static  HttpServiceMethod parseAnnotations(  Retrofit retrofit, Method method, RequestFactory requestFactory) {// 省略其他代码...CallAdapter callAdapter =  createCallAdapter(retrofit, method, adapterType, annotations);}

我们发现是通过 createCallAdapter 方法来创建 CallAdapter

private static  CallAdapter createCallAdapter(  Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {try {  //noinspection unchecked  return (CallAdapter) retrofit.callAdapter(returnType, annotations);} catch (RuntimeException e) {  throw methodError(method, e, "Unable to create call adapter for %s", returnType);}}

里面是通过 retrofit.callAdapter 来获取 CallAdapter

public final class Retrofit {    public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {        return nextCallAdapter(null, returnType, annotations);    }    public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,      Annotation[] annotations) {                // 因为 skipPast = null,所以 start = 0        // 也就是获取集合里面第一个 CallAdapterFactory,也就是我们自定义的 MyCallAdapterFactory        int start = callAdapterFactories.indexOf(skipPast) + 1;        for (int i = start, count = callAdapterFactories.size(); i < count; i++) {          // 也就是我们自定义的 MyCallAdapter          CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);          if (adapter != null) {            return adapter;          }        }        // 省略其他代码...    }}

好,现在我们知道了 CallAdapter 是怎么创建了。在 HttpServiceMethod.parseAnnotations() 方法中创建完 CallAdapter ,然后将其传给了 HttpServiceMethod 的子类构造方法:

  • CallAdapted
  • SuspendForResponse
  • SuspendForBody

这些类重写了 HttpServiceMethod.adapt 方法,里面实际上就是调用了传进来的 CallAdapter.adapt 方法。

我们知道在动态代理里调用了 HttpServiceMethod.invoke 方法:

@Override final @Nullable ReturnT invoke(Object[] args) {    Call call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);    return adapt(call, args);}

CallAdapter.adapt 方法的 call 参数,其实就是 OkHttpCall,真正的请求操作都是封装在 OkHttpCall 里。

invoke 方法里面调用了 HttpServiceMethod.adapt 方法,其实也就是调用了我们自定义 CallAdapteradapt 方法。

这个时候终于关联到我们自定义的 MyCallAdapter 了,在 MyCallAdapter 中调用 call.enenque 方法来执行网络请求,其实这里的 call 就是 OkHttpCall

然后将网络请求的返回结果(包括异常)交给我们自定义的 Callback.

至此,整个自定义的 CallAdapter 的执行过程我们就介绍完毕了。

小结

本文详细介绍了 Retrofit 如何自定 CallAdapter 达到统一处理网络错误的目的。文章的最后还介绍了 CallAdapter 的执行原理。

本文涉及到的代码都在我的 AndroidAll GitHub 仓库中。该仓库除了 Retrofit,还有Android 程序员需要掌握的技术栈,如:程序架构、设计模式、性能优化、数据结构算法、Kotlin、Flutter、NDK、Router、RxJava、Glide、LeakCanary、Dagger2、Retrofit、OkHttp、ButterKnife、Router 等等,持续更新,欢迎 star。

更多相关文章

  1. Kotlin入门(三)使用协程
  2. 关于 Android(安卓)opencv 屏幕方向的bug
  3. Volley源码解析
  4. Android基础部分填坑
  5. Android应用程序消息处理机制(Looper、Handler)分析(3)
  6. Android基础之异步消息处理机制
  7. 【xml String format】error: Multiple substitutions specified
  8. Android(安卓)NDK开发之旅37--FFmpeg转码压缩
  9. Android(安卓)TextView长按复制的实现方法

随机推荐

  1. Android(安卓)studio 升级到4.0-4.0.1版
  2. Android初级教程理论知识(第六章广播接受
  3. android实现蓝牙文件发送的实例代码,支持
  4. android5.0以后 framework 添加资源 编译
  5. 【Android注释技巧】Android函数上面的注
  6. Android(安卓)MMS源码结构
  7. Android(安卓)APK 签名机制
  8. Android上HDMI介绍(基于高通平台)-- Overla
  9. Android(安卓)Studio VS Eclipse (还在用E
  10. Android(安卓)AIDL实例解析