源码之 Retrofit

  • 沿着使用追溯源码
  • Retrofit 的使用过程为:
  1. 创建 Service 接口
  2. 创建 Retrofit 对象
  3. 创建实现了 Service 接口的代理对象
  4. 调用代理对象的请求方法,发起同步/异步请求并获取回调
  • 总结:
  1. Retrofit 采用动态代理创建实现了 Service 接口的代理对象,当我们调用 service 的请求方法 method 方法时,会执行 InvocationHandler.invoke 方法。在 invoke 方法中,会调用 loadServiceMethod 方法。
  2. 在 loadServiceMethod 方法内部,如果缓存中已有 method,直接返回对应的 ServiceMethod 对象;否则,会通过大量的反射对方法注解进行解析,生成对应的 ServiceMethod 对象并返回。
  3. 这里返回的 ServiceMethod 实际上是 SuspendForBody 对象,SuspendForBody 继承于 HttpServiceMethod,HttpServiceMethod 继承于 ServiceMethod。
  4. 接着调用 ServiceMethod.invoke 方法,会走到 HttpServiceMethod.invoke 方法,在 invoke 方法中,创建 OkHttpCall 对象,并进一步封装成 ExecutorCallbackCall 对象(默认)。实际发起网络请求的就是 OkHttpCall 对象。
  5. OkHttpCall 发起网络请求,通过 ConverterFactory 将网络请求返回的 Response 数据解析成 Java 对象,并通过 MainThreadExecutor 将回调转发至主线程。

一、疑惑

  1. 为什么会出现 Retrofit?
    1.1. Retrofit 的出现解决了当时使用存在的一些什么问题?
    1.2. 使用它有什么便利的地方?

二、使用

  • 创建 Service 接口
public interface ApiService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
}
  • 使用
// 1。创建retrofit
val retrofit = Retrofit.Builder().baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .build()
    
// 2。创建代理对象
val service = retrofit.create(ApiService::class.java)

// 3。调用请求方法
val repos = service.listRepos("octocat")

// 4。发起请求并获取回调
repos.enqueue(object : Callback<List<Repo>> {
    override fun onResponse(call: Call<List<Repo>>, response: Response<List<Repo>>) {
        LogUtil.e("result: " + response.body())
    }

    override fun onFailure(call: Call<List<Repo>>, t: Throwable) {
        LogUtil.e("onFailure: " + t.toString())
    }
})

三、分析

1、创建 Retrofit

  • Retrofit 对象的初始化采用了建造者模式
    在这里插入图片描述
  • 涉及了5个对象
  1. baseUrl
  2. CallFactory:也就是 OkHttpClient
  3. Executor:用于线程切换
  4. CallAdapterFactory:将 OkHttpCall 适配/封装成具体的 Call(copy 话术:对请求的中间过程进行适配的工厂)
  5. ConverterFactory:对网络请求返回的 Response 数据进行解析

2、创建代理对象

在这里插入图片描述

  • Retrofit 采用动态代理,创建声明了 Service 接口的实现对象
  • 当我们调用 service 的 请求方法时,会执行 InvocationHandler.invoke 方法
  • 动态代理具体知识可看:代理模式之动态代理

3、解析请求方法

在这里插入图片描述
① Retrofit.validateServiceInterface
在这里插入图片描述

  • 对定义在 Service 接口中的所有请求方法进行解析

② Retrofit.loadServiceMethod
在这里插入图片描述
在这里插入图片描述

  • 通过 ConcurrentHashMap(线程安全)做 Method——>ServiceMethod 的映射关系存储
  • 如果 serviceMethodCache 中已经存在,直接返回对应的 ServiceMethod;否则,进行注解解析
  • 因为解析请求方法注解使用了大量的反射操作,所以这里做了缓存工作,即便多次调用统一请求方法,也只需做一次解析工作

ServiceMethod.parseAnnotations
在这里插入图片描述


3.1 请求端的信息解析

RequestFactory.parseAnnotations
在这里插入图片描述
RequestFactory.parseMethodAnnotation
在这里插入图片描述

  • 主要是对于方法注解的解析,例如@Header、@GET、@POST等

RequestFactory.parseParameter
在这里插入图片描述

  • 第一个处,主要是对参数注解的解析

RequestFactory.parseParameterAnnotation在这里插入图片描述
Retrofit.requestBodyConverter
在这里插入图片描述

  • 对 @Body 注解的解析
    在这里插入图片描述
  • 由于传入的 skipPast 为 null,所以 start = 0。
  • 最终使用谁,取决于 factory.requestBodyConverter 方法的返回值是否为 null

3.2 响应端的信息解析

HttpServiceMethod.parseAnnotations
在这里插入图片描述
① HttpServiceMethod.createCallAdapter
在这里插入图片描述
HttpServiceMethod.callAdapter
在这里插入图片描述

  • 这里用到了创建 Retrofit 时配置的 CallAdapterFactory
  • 由于传入的 skipPast 为 null,所以 start = 0。最终使用谁,取决于获取的 CallAdapter 是否为null

Retrofit.Build.build
在这里插入图片描述

  • 创建 Retrofit 时 传入的 CallAdapterFactory

Platform.defaultCallAdapterFactories在这里插入图片描述

  • 所以 ① 处最后返回的就是 DefaultCallAdapterFactory.get

  • 以支持 Kotlin 的 suspend function 为例,并且返回值类型不为 Response 类型,那么就会走到 else 分支里,返回 SuspendForBody 对象

至此,对于请求方法的解析已经完毕,都存放到 SuspendForBody 中,接下来我们就可以从实际发起网络请求开始继续往下分析


4、调用请求方法并回调

动态代理的 InvocationHandler
在这里插入图片描述

  • 找到 Method 方法对应的 ServiceMethod 对象,调用其 invoke 方法
  • 在上诉的分析中,我们已经知道了 loadServiceMethod 返回的 ServiceMethod 其实就是 SuspendForBody 对象【SuspendForBody 继承于 HttpServiceMethod,HttpServiceMethod 继承于 ServiceMethod】
  • 所以,invoke 方法会走到 HttpServiceMethod 的 invoke 方法

HttpServiceMethod.invoke
在这里插入图片描述

  • 生成了 OkHttpCall 对象

SuspendForBody
在这里插入图片描述

  • call:是 HttpServiceMethod.invoke 方法中创建的 OkHttpCall 对象
  • callAdapter:是 ① 处中的最后返回的 DefaultCallAdapterFactory.get ,在 ② 处中传入

DefaultCallAdapterFactory.get
在这里插入图片描述

  • DefaultCallAdapterFactory.get 最后返回的是 ExecutorCallbackCall 对象
    在这里插入图片描述
  • 经过 DefaultCallAdapterFactory 的适配,OkHttpCall 变成了 ExecutorCallbackCall 对象
  • isNullable 为 false,最后调用的是 KotlinExtensions.await 方法

KotlinExtensions.await
在这里插入图片描述
ExecutorCallbackCall
在这里插入图片描述

  • delegate 就是 OkHttpCall,ExecutorCallbackCall.enqueue 就会执行到 OkHttpCall.enqueue 方法

OkHttpCall.enqueue
在这里插入图片描述
① OkHttpCall.createRawCall
在这里插入图片描述
② OkHttpCall.parseResponse
在这里插入图片描述

  • responseConverter 涉及到 ConverterFactory。那我们熟悉 GsonConverterFactory 举例

GsonConverterFactory
在这里插入图片描述
GsonResponseBodyConverter.convert
在这里插入图片描述
TypeAdapter.read
在这里插入图片描述

  • read 方法可以将 JSON 字符串转换成 Java 对象,对网络请求返回的 Response 数据解析成我们声明的对象

③ ExecutorCallbackCall 回调给 OkHttpCall
在这里插入图片描述
① Retrofit.Builder.build
在这里插入图片描述

① 默认是 Android 平台
在这里插入图片描述

  • 默认是 Android 平台,生成的 Executor 是 MainThreadExecutor
  • 最后会调用到 MainThreadExecutor.execute 方法,利用 handler 切换到主线程

② OkHttpCall 回调给 KotlinExtensions
在这里插入图片描述

  • resume 方法将执行权交还给挂起点。到此结束!

四、疑惑解答

  • 说到为什么会出现 Retrofit,就得看看在 Retrofit 出现前,怎么使用 OkHttp 进行网络请求:
    在这里插入图片描述
  • 我们可以从中知道使用 OkHttp 所存在的一些问题
  1. 网络请求的接口配置繁琐,需要配置请求头、请求体和请求参数
  2. 网络请求返回的 Response 数据需要手动解析,且不能够复用
  3. 无法自动进行线程的切换
  • 综上所述,就有了 Retrofit 的出现。Retrofit 是基于 OkHttp 进行的封装。

  • 从功能上说,Retrofit 完成了网络请求接口的封装,网络请求返回数据的解析和线程的自动切换,解决了 OkHttp 使用时存在的一些问题

  • 从代码结构上说,Retrofit 提供了很多注解,在我们配置网络请求时,简化了代码,且解耦

  • 参考资料:
    https://blog.csdn.net/xlh1191860939/article/details/108111945?spm=1001.2014.3001.5501
    https://www.jianshu.com/p/d99a680e765d

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值