Android Retrofit 源码系列(二)~ 自定义 CallAdapter

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 装成我们要的 MyCalloverride 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,则不使用 MyCallAdapterif (getRawType(returnType) != MyCall::class.java) return null// 返回类型的泛型校验check(returnType is ParameterizedType) { "MyCall must have generic type (e.g., MyCall)" }val responseType = getParameterUpperBound(0, returnType)// 实际上是 MainThreadExecutorval executor = retrofit.callbackExecutor()// 返回我们自定义的 MyCallAdapterreturn 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"@JvmStaticfun 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")@FormUrlEncodedfun register2(@Field("username") username: String,@Field("mobile") mobile: String): MyCall>
}private fun customCall() {// MyCallval 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 uncheckedreturn (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,也就是我们自定义的 MyCallAdapterFactoryint start = callAdapterFactories.indexOf(skipPast) + 1;for (int i = start, count = callAdapterFactories.size(); i < count; i++) {// 也就是我们自定义的 MyCallAdapterCallAdapter 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。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部