Retrofit源码全方面解析
如今作为一个Android开发者,网络请求这块离不开square公司的全家桶,今天我们就来分析一下其中的Retrofit框架的源码。(源码版本2.8.1)
为什么使用Retrofit
因为方便、直观,和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类
对于Retrofit类的成员初始化,使用了建造者模式。
Builder类的三个构造器。我们再看Builder.build()方法:
-
第一个红框:如果我们没有提供OkHttpClient对象,那么框架内部会为我们创建一个OkHttpClient对象。
-
第二个红框:这里的callbackExecutor,实际上是为了最后请求结果的回调服务的,将执行流程从子线程切换到主线程。
通过Handler,将执行流程切换到主线程
- 第三个红框:将我们通过Retrofit.Builder配置的CallAdapterFactory放置到Retrofit对象中,并且添加一个默认的CallAdapterFactory
至于这个DefaultCallAdapterFactory里面的逻辑我们放到后面去分析。
- 第四个红框:将我们通过Retrofit.Builder配置的ConvertFactory放置到Retrofit对象中,并且前后各放入了ConvertFactory。
最后,创建Retrofit对象并返回。
Retrofit.create()方法出发
这里只需要注意两个地方:
- validateServiceInterface()方法,这个方法会来解析对应的接口方法的注解信息等
- 通过Proxy.newProxyInstance(),返回了一个动态代理对象,供后续的接口请求使用
Retrofit.validateServiceInterface()方法
- 第一个红框:因为动态代理的限制,动态代理类实际上是抽象类Proxy的子类,由于Java是单继承的,所以用于动态代理的必须是接口
- 第二个红框:根据传入的接口的Class对象,查找其父接口的信息,并且对于接口泛型进行了检查(不支持)
- 第三个红框:对于定义在service接口中的一个个请求方法进行解析。
那么接下来的重点就是来看loadServiceMethod()方法的实现。
Retrofit.loadServiceMethod()
这块的逻辑很简单,通过一个map做存储Method对象到ServiceMethod的映射关系。已经在ServiceMethodCache中存在的,直接返回对应的ServiceMethod,因为解析请求方法注解的过程设计到大量的反射操作(后面会看到),这样就可以实现无论请求方法调用多少次,而解析的过程只有一次。
ServiceMethod.parseAnnotations()
RequestFactory.parseAnnotations()
我们只需要理解这两个方法即可
- RequestFactory.Builder.parseMethodAnnotation():主要是对于方法注解的解析,例如@Header、@GET、@POST等
- RequestFactory.Builder.parseParameter():对于参数注解的解析
这里只需要注意两个地方:先说第二个红框,这个地方是Retrofit对于Kotlin协程方法的支持,在笔者之前的文章中以及介绍过;第一个红框,这个parseParameterAnnotation()方法实现的代码很长,我们现在重点关注这一段:
这段是对于@Body注解的解析。
可以看到,这里会用上之前给Retrofit对象配置的ConverterFactory
假定我们这里添加了两个ConverterFactory:ScalarsConverterFactory以及GsonConverterFactory。还记得在之前提到BuiltInConverters以及defaultConvert
换句话说,convertFactories现在内部的结构如下:
由于传入的skipPast为null,所以start为0。最终使用谁,取决于factory.requestBodyConverter()方法的返回值是否为null。
- BuiltInCoverts:此时返回null
- ScalarsConverterFactory:只要不是基本数据类型和String类型,返回null
- GsonConverterFactory:它就不返回null了。
那么流程最多到这,就会找到对应的converter。
从这里也可以看出,一旦我们同时添加ScalarsConverterFactory和GsonConverterFactory,那么ScalarsConverterFactory在配置时一定要先与GsonConverterFactory添加。
HttpServiceMethod.parseAnnotations()
通过ServiceMethod.parseAnnotations()的处理,将请求端相关信息已经解析完毕了,我们下面要分析的方法就是对响应端信息的解析。
- 第一个红框:这里我们就会用到前面为Retrofit配置的CallAdapterFactory。
看到这,发现和ConverterFactory是同样的套路。我们前面配置过两个Factory:RxJava2CallAdapterFactory和ObserveOnMainCallAdapterFactory,所以callAdapterFactories的结构如下:
由于我们想分析支持Kotlin协程的逻辑,这俩就不看了(使用协程这俩就不用添加了),如果项目中使用到RxJava的同学可以自行深入分析一下。这样,这里返回的就是DefaultCallAdapterFactory。
- 第二个红框:我们这里以支持Kotlin的suspend function为例,并且返回值类型不为Response类型,那么就会走到else分支里,将SuspendForBody对象返回回去。
这是SuspendForBody的类层级关系:
至此,对于请求方法的解析已经完毕,都存放到SuspendForBody中,接下来我们就可以从实际发起网络请求开始继续往下分析。
动态代理的InvocationHandler
对于在Object中定义的方法,不做特殊处理;然后通过loadServiceMethod()方法找到Method对象对应的ServiceMethod对象,调用其invoke()方法。在前面的基础上,我们知道此时的ServiceMethod对象实际上是SuspendForBody对象,SuspendForBody类的层级关系我们已经知道,所以执行流程会走到HttpServiceMethod的invoke()方法里:
callAdapter基于前面的分析,这里是DefaultCallAdapterFactory的get()方法返回的:
此时我们需要回头看一下Retrofit.Builder.build()方法:
如果我们为其配置callbackExecutor,那么
那么实际上意味着通过DefaultConverter的转换,变成了
最后会走到KotlinExtensions.await()中:
await()是Call的一个扩展方法,那么这里就会涉及到在Java中调用Kotlin扩展方法的知识,可参考笔者的另一篇文章。
此时,执行流程就会走到ExecutorCallbackCall的enqueue()方法:
这里的delegate就是OkHttpCall,大家可以往前追溯一下。
此时,执行流程就会走到OkHttpCall的enqueue()方法:
- 第一个红框:会在这创建OkHttp框架中Call
通过这个Call,调用异步请求enqueue()方法,通过OkHttp发起网络请求。
- 第二个红框:解析OkHttp请求返回的Response
到这里,就再次与ConverterFactory扯上关系。比如GsonConverterFactory里:
这样,就通过Gson将JSON串转换成Java对象返回。
- 第三个红框:通过回调,将执行逻辑回调回下面的代码
这样,就确保将执行流程返回到主线程,并且继续回调:
在成功的情况下,通过resume()方法将执行权交还给挂起点:
这里只走了一遍成功的情况,失败的情况也可按照此方法分析,在这里就不再赘述了。
总结
至此,我们Retrofit源码的分析也告一段落了。Retrofit框架的源码十分优秀,类的结构设计非常清晰,运用了大量的设计模式,如门面模式、代理模式、建造者模式等。了解了内部代码结构可以指导我们在使用时遇到的问题,如同时使用ScalarsConverterFactory和GsonConverterFactory时要注意配置的顺序,更多的是学习代码设计思想,运用到日常开发中去,使得我们的代码耦合性低,易扩展。
更多相关文章
- Mac os下android源码下载及安装
- Android Retrofit 源码系列(五)~ 设计模式分析
- Android 子线程更新UI的几种方法
- android加载字体内存泄漏的处理方法
- 【Android】获取图片和视频缩略图
- Android Studio运行main方法报错 SourceSet with name ‘main‘
- Android使用HttpClient下载图片
- android切换到后台,返回后图片纹理丢失