如今作为一个Android开发者,网络请求这块离不开square公司的全家桶,今天我们就来分析一下其中的Retrofit框架的源码。(源码版本2.8.1)
因为方便、直观,和OkHttp的结合天衣无缝:
@GET("weather")
fun weather(@Query("latitude") latitude: String, @Query("longitude") longitude: String): Flowable<String>
通过注解,对于这样的一个GET请求,请求参数以及返回结果,一目了然。并且还提供了多种CallAdapter以及Convert:
RxJava2CallAdapterFactory:使得Retrofit可以RxJava结合使用
ObserveOnMainCallAdapterFactory: 根据官方demo自定义的CallAdapterFactory,这样就使得当Retrofit和RxJava结合使用时,我们不用每次对请求方法调用时添加如下代码:
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
GsonConverterFactory:Gson和Retrofit结合使用,使得Body提交以及Response解析时面向对象编程
ScalarsConverterFactory:当提交的Body或者Response是如下类型时:
我们可以使用该转换工厂,因为如果使用Gson转换工厂时,会抛异常:
Expected a string but was BEGIN_OBJECT at line 1 column 2 path $
这是使用String类型时的异常信息。
并且,Retrofit2.6之后,从框架内部提供了对Kotlin协程的支持,使得我们可以使用协程特性。
最后提一嘴,Retrofit的这种形式同SpringMVC中的声明方式及其类似。
对于Retrofit类的成员初始化,使用了建造者模式。
Builder类的三个构造器。我们再看Builder.build()方法:
第一个红框:如果我们没有提供OkHttpClient对象,那么框架内部会为我们创建一个OkHttpClient对象。
第二个红框:这里的callbackExecutor,实际上是为了最后请求结果的回调服务的,将执行流程从子线程切换到主线程。
通过Handler,将执行流程切换到主线程
至于这个DefaultCallAdapterFactory里面的逻辑我们放到后面去分析。
最后,创建Retrofit对象并返回。
这里只需要注意两个地方:
那么接下来的重点就是来看loadServiceMethod()方法的实现。
这块的逻辑很简单,通过一个map做存储Method对象到ServiceMethod的映射关系。已经在ServiceMethodCache中存在的,直接返回对应的ServiceMethod,因为解析请求方法注解的过程设计到大量的反射操作(后面会看到),这样就可以实现无论请求方法调用多少次,而解析的过程只有一次。
我们只需要理解这两个方法即可
这里只需要注意两个地方:先说第二个红框,这个地方是Retrofit对于Kotlin协程方法的支持,在笔者之前的文章中以及介绍过;第一个红框,这个parseParameterAnnotation()方法实现的代码很长,我们现在重点关注这一段:
可以看到,这里会用上之前给Retrofit对象配置的ConverterFactory
假定我们这里添加了两个ConverterFactory:ScalarsConverterFactory以及GsonConverterFactory。还记得在之前提到BuiltInConverters以及defaultConvert
换句话说,convertFactories现在内部的结构如下:
由于传入的skipPast为null,所以start为0。最终使用谁,取决于factory.requestBodyConverter()方法的返回值是否为null。
那么流程最多到这,就会找到对应的converter。
从这里也可以看出,一旦我们同时添加ScalarsConverterFactory和GsonConverterFactory,那么ScalarsConverterFactory在配置时一定要先与GsonConverterFactory添加。
通过ServiceMethod.parseAnnotations()的处理,将请求端相关信息已经解析完毕了,我们下面要分析的方法就是对响应端信息的解析。
看到这,发现和ConverterFactory是同样的套路。我们前面配置过两个Factory:RxJava2CallAdapterFactory和ObserveOnMainCallAdapterFactory,所以callAdapterFactories的结构如下:
由于我们想分析支持Kotlin协程的逻辑,这俩就不看了(使用协程这俩就不用添加了),如果项目中使用到RxJava的同学可以自行深入分析一下。这样,这里返回的就是DefaultCallAdapterFactory。
这是SuspendForBody的类层级关系:
至此,对于请求方法的解析已经完毕,都存放到SuspendForBody中,接下来我们就可以从实际发起网络请求开始继续往下分析。
对于在Object中定义的方法,不做特殊处理;然后通过loadServiceMethod()方法找到Method对象对应的ServiceMethod对象,调用其invoke()方法。在前面的基础上,我们知道此时的ServiceMethod对象实际上是SuspendForBody对象,SuspendForBody类的层级关系我们已经知道,所以执行流程会走到HttpServiceMethod的invoke()方法里:
callAdapter基于前面的分析,这里是DefaultCallAdapterFactory的get()方法返回的:
此时我们需要回头看一下Retrofit.Builder.build()方法:
那么实际上意味着通过DefaultConverter的转换,变成了
最后会走到KotlinExtensions.await()中:
await()是Call的一个扩展方法,那么这里就会涉及到在Java中调用Kotlin扩展方法的知识,可参考笔者的另一篇文章。
此时,执行流程就会走到ExecutorCallbackCall的enqueue()方法:
这里的delegate就是OkHttpCall,大家可以往前追溯一下。
此时,执行流程就会走到OkHttpCall的enqueue()方法:
通过这个Call,调用异步请求enqueue()方法,通过OkHttp发起网络请求。
到这里,就再次与ConverterFactory扯上关系。比如GsonConverterFactory里:
这样,就通过Gson将JSON串转换成Java对象返回。
这样,就确保将执行流程返回到主线程,并且继续回调:
在成功的情况下,通过resume()方法将执行权交还给挂起点:
这里只走了一遍成功的情况,失败的情况也可按照此方法分析,在这里就不再赘述了。
至此,我们Retrofit源码的分析也告一段落了。Retrofit框架的源码十分优秀,类的结构设计非常清晰,运用了大量的设计模式,如门面模式、代理模式、建造者模式等。了解了内部代码结构可以指导我们在使用时遇到的问题,如同时使用ScalarsConverterFactory和GsonConverterFactory时要注意配置的顺序,更多的是学习代码设计思想,运用到日常开发中去,使得我们的代码耦合性低,易扩展。