用途
Retrofit is the class through which your API interfaces are turned into callable objects.
译:Retrofit通过设置的API接口转换为可以被调用的类。
所以,这样我们就可以知道Retrofit是一个HTTP框架,那么在没有Retrofit之前,我们是如何请求的。
- build Request参数
- 因为网络请求是一个耗时操作,Android不允许在主线程中进行,所以需要线程或利用Excutor创建新线程
- 异步后,通过运行非主线程来进行网络请求
- 请求成功,获取到服务器返回的数据之后,callback回调给应用上层
- 进行切换线程,数据处理等等
发展历程
- 手写上述过程
- 官方出了AsyncTask
- 第三方库Volly…
优缺点、对比什么的就先挖个坑
Retrofit
接下来我们来看看Retrofit有什么能力取代其他框架的。
举个栗子
1 | Retrofit retrofit = new Retrofit.Builder() |
1 | public interface ZhiHuApi { |
分析流程
前面叙述了没有 Retrofit 是如何进行网络请求的,那我们按照给出步骤来看看Retrofit是如何实现的。
- build request(API参数配置)
- executor
- 解析数据,返回T(需要的数据类型,下同)给上层
Retrofit的版本
- 通过注解配置API参数
- CallAdapter(理解为 executor)
- Converter(解析数据并转换为T)
创建Retrofit 对象
1 | Retrofit retrofit = new Retrofit.Builder() |
定义API
1 | public interface ZhiHuApi { |
这里使用到注解@GET
、@PATH
获取API实例
1 | ZhiHuApi zhiHuApi = retrofit.create(ZhiHuApi.class); |
create方法源码
1 | @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety. |
动态代理?(不懂,逃…)
动态生成接口的实现类(动态),并创建它的实例(代理)。代理把对接口的调用转发给InvocationHandler
实例,在 InvocationHandler 的实现中,执行真正的逻辑。
没错,下面就是 InvocationHandler 的源码啦
1 | return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service }, |
为什么要用动态代理?因为对接口的所有方法的调用都会集中转发到 InvocationHandler 的 invoke 函数中,我们可以集中进行处理,更方便了。
调用 API 方法
这里的代码和RxJava结合了
1 | Network.getZhiHuApi() |
在这里完成了HTTP请求,并将数据转化为需要的类型了。所以这里的很很很重要的地方。
那么是如何进行请求和转换的呢?
进行HTTP请求&数据转换(重要)
1 | ServiceMethod<Object, Object> serviceMethod = |
这几行代码完成了ServiceMethod
、build OkHttpCall
、CallAdapter adapt
ServiceMethod< R,T>
/* Adapts an invocation of an interface method into an HTTP call. /
ServiceMethod 作用在上面已经给出,翻译过来就是将接口方法转化为HTTP调用
一个 ServiceMethod 对应着一个API接口方法,第一行中的 loadServiceMethod 方法的作用是用于加载 ServiceMethod
1 | ServiceMethod<?, ?> loadServiceMethod(Method method) { |
在 loadServiceMethod 中你会发现它实现了缓存机制,同一个 Api 的同一个方法,只会被创建一次。
ServiceMethod 的构造方法
1 | ServiceMethod(Builder<R, T> builder) { |
成员变量:callFactory 、callAdapter 、responseConverter 、parameterHandlers
- callFactory 负责创建 HTTP 请求,HTTP 请求被抽象为 okhttp3.call 类,表示随时可以执行 HTTP请求
- callAdapter 将 retrofit2.Call< T> 转为 T (retrofit2.Call
表示对一个 Retrofit 方法的调用),这一个过程会执行一个 HTTP 请求,服务器返回数据(OkHttp3.call实现),并且把数据转换为声明的 T 类型对象(Converter<?, String> 实现) - responseConverter (Converter
类型) 负责将服务器返回的数据转化为 T 类型的对象 - parameterHandlers 负责解析API 定义时候每个方法的参数,并且在构造HTTP请求的时候设置参数
callFactory
1 | this.callFactory = builder.retrofit.callFactory(); |
我们在构建 retrofit 的时候就会指定一个 callFactory ,如果不指定,系统会默认设置一个 okhttp3.OkHttpClient
1 | /** |
callAdapter
1 | private CallAdapter<T, R> createCallAdapter() { |
先进行一些检查,然后 return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
由 retrofit 提供。
在 Retrofit 类内部,遍历CallAdapter.Factory
列表,由工厂提供,如果工厂没有提供需要的 callAdapter 就抛异常。
我们可以在构建 retrofit 时指定 callAdapter。
responseConverter
1 | private Converter<ResponseBody, T> createResponseConverter() { |
responseConverter 由 retrofit 提供,看代码可以知道原理和 callAdapter 一致,先看工厂里面有没有,没有就报异常,同样可以再构建 retrofit 时指定。
parameterHandlers
1 | private ParameterHandler<?> parseParameter( |
作用就是解析每个参数使用的注解类型(如 Path,Query,Field 等),对每种类型进行单独的处理。
构造 HTTP 请求时,我们传递的参数都是字符串,那 Retrofit 是如何把我们传递的各种参数都转换为 String 的呢?
还是由 Retrofit 类提供 converter
Converter.Factory 除了提供上一小节提到的 responseBodyConverter
,还提供 requestBodyConverter
和 stringConverter
API 方法中除了 @Body
和 @Part
类型的参数,都利用 stringConverter 进行转换,而 @Body 和 @Part 类型的参数则利用 requestBodyConverter 进行转换。
这三种 converter 都是通过“询问”工厂列表进行提供,而工厂我们可以在构造 Retrofit 对象时进行添加。
三种工厂( okhttp3.Call.Factory,CallAdapter.Factory 和 Converter.Factory)
OkHttpCall
OkHttpCall 实现了 retrofit2.Call,分别使用 execute() 和 equeue(Callback< T> callback) 执行同步或异步请求
同步请求
1 | @Override |
主要步骤
- 创建 OkHttp3.Call
- 执行网络请求
- 解析服务器返回的数据
1 | private okhttp3.Call createRawCall() throws IOException { |
在 createRawCall 中调用 serviceMethod.toRequest(args) 来创建 request, args 就是来自于我们之前的 parameterHandlers
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
创建 okhttp3.Call, callFactory在之前已经做过分析了。
利用 execute() 来执行网络请求,这个方法是阻塞的,执行完毕之后将返回收到的响应数据。
收到响应数据之后,先进行状态码的检查,通过检查之后调用 serviceMethod.toResponse(catchingBody) 来把响应数据转化为了需要的数据类型对象。在 toResponse 函数中,之前分析的 responseConverter 也派上了用场。
异步请求
异步的不同之处在于异步交给 okhttp3.Call#enqueue(Callback responseCallback) 来实现的,并在 callback 中调用 parseResponse 解析响应数据,并转发给传入的 callback。
CallAdapter(数据转换)
1 | private CallAdapter<T, R> createCallAdapter() { |
作用就是将 retrofit2.Call R 转化为 T 。
retrofit 的 adapter模块
retrofit 内置了两个 adapterFactory
- DefaultCallAdapterFactory 直接将参数返回
- ExecutorCallAdapterFactory 在异步调用时在指定的Eecutor上执行回调
retrofit 子模块实现了更多的 adapterFactory
- GuavaCallAdapterFactory
- Java8CallAdapterFactory
- RxJavaCallAdapterFactory
主要分析 RxJavaCallAdapterFactory
RxJavaCallAdapterFactory#get 方法中对返回值的类型进行了检查,只支持 rx.Single,rx.Completable 和 rx.Observable,这里主要关注对 rx.Observable 的支持。
RxJavaCallAdapterFactory#getCallAdapter 方法中对返回值的泛型类型进行了进一步检查
例如我们声明的返回值类型为 Observable< List< Repo>>,泛型类型就是 List< Repo>
这里对 retrofit2.Response 和 retrofit2.adapter.rxjava.Result 进行了特殊处理,有单独的 adapter 负责进行转换,其他所有类型都由 SimpleCallAdapter 负责转换。
SimpleCallAdapter#adapter
1 | @Override |
创建了一个 Observable,它的逻辑由 CallOnSubscribe 类实现,同时使用了一个 OperatorMapResponseToBodyOrError 操作符,用来把 retrofit2.Response 转为我们声明的类型,或者错误异常类型。
CallOnSubscribe#call
1 |
|
- clone 了原来的 call,因为 okhttp3.Call 是只能用一次的,所以每次都是新 clone 一个进行网络请求;
- 创建了一个叫做 RequestArbiter 的 producer;
- 把这个 producer 设置给 subscriber
大部分情况下 Subscriber 都是被动接受 Observable push 过来的数据,但要是 Observable 发得太快,Subscriber 处理不过来,那就有问题了,所以就有了一种 Subscriber 主动 pull 的机制,而这种机制就是通过 Producer 实现的。
给 Subscriber 设置 Producer 之后(通过 Subscriber#setProducer 方法),Subscriber 就会通过 Producer 向上游根据自己的能力请求数据(通过 Producer#request 方法),而 Producer 收到请求之后(通常都是 Observable 管理 Producer,所以“相当于”就是 Observable 收到了请求),再根据请求的量给 Subscriber 发数据。
(不就是rxjava 背压???)
RequestArbiter#request
1 |
|
实际干活的逻辑就是执行 call.execute(),并把返回值发送给下游。
OperatorMapResponseToBodyOrError#call
1 |
|
调用 response.body() 并发送给下游。
这里,body() 返回的就是我们声明的泛型类型了
至于 Retrofit 是怎么把服务器返回的数据转为我们声明的类型的,那就看 responseBodyConverter,下面讲道。
执行流程
- Observable.subscribe,触发 API 调用的执行
- CallOnSubscribe#call,clone call,创建并设置 producer
- RequestArbiter#request,subscriber 被设置了 producer 之后最终调用 request,在 request 中发起请求,把结果发给下游
- OperatorMapResponseToBodyOrError$1#onNext,把 response 的 body 发给下游
- 最终就到了 subscribe 传入的回调里面了
retrofit-converters 模块
retrofit 内置 BuiltInConverters,只能处理 ResponseBody, RequestBody 和 String 类型的转化。
retrofit-converters 中的子模块则提供了 JSON,XML,ProtoBuf 等类型数据的转换功能,而且还有多种转换方式可以选择。这里主要关注 GsonConverterFactory
1 |
|
根据目标类型,利用 Gson#getAdapter 获取相应的 adapter,转换时利用 Gson 的 API 即可.
至于Gson就又是一篇文章了。
参考大神piasy