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()方法实现的代码很长,我们现在重点关注这一段:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AlrhqS6n-1597845866254)(/Users/xlh/Library/Application Support/typora-user-images/image-20200817220524470.png)]
这段是对于@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。

在这里插入图片描述
在这里插入图片描述

(img-sIrybNjR-1597845866262)(/Users/xlh/Library/Application Support/typora-user-images/image-20200819204758017.png)]

看到这,发现和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时要注意配置的顺序,更多的是学习代码设计思想,运用到日常开发中去,使得我们的代码耦合性低,易扩展。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值