Retrofit概要
- Retrofit是一个网络请求框架的封装,把每一个http的api请求变成java接口,只是一个restful风格网络请求框架的封装,而不是网络请求框架,其主要工作都由其内核okhttp来完成。Retrofit主要完成数据的转化与适配。Retrofit设计模式使用了许多设计模式,所以具有很多的扩展性,能与Rxjava、json、okhttp等主流库进行无缝对接。
Retrofit设计模式
- 构建者模式
- 工厂方法
- 外观模式
- 策略模式
- 适配器模式
- 动态代理
- 观察者模式
Retrofit快速使用
- 定义网络请求接口
- 定义接口方法
- 构建
Retrofit
- 获取网路请求接口
- 获取请求
Call
- 执行同/异步网络请求
public interface MyInterface {
@GET("www.baidu.com/{user}/first")
Call getService(@Path("user")String user);
@GET(".../...")
Call> getCall();
}
复制代码
//java
Retrofit retrofit=new Retrofit.Builder()
.baseUrl("http://www.baidu.com")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
MyInterface myInterface = retrofit.create(MyInterface.class);
retrofit2.Call call = iMyService.getService("lisi");
call.enqueue(new retrofit2.Callback() {
@Override
public void onResponse(retrofit2.Call call, retrofit2.Response response) {
}
@Override
public void onFailure(retrofit2.Call call, Throwable t) {
}
});
复制代码
//kotlin
var retrofit = Retrofit.Builder()
.baseUrl("http://www.baidu.com")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
var myInterface = retrofit.create(MyInterface::class.java)
var call = myInterface.getCall()
call.execute()
call.enqueue(object : Callback<List<String>> {
override fun onResponse(call: Call<List<String>>, response: Response<List<String>>) {
}
override fun onFailure(call: Call<List<String>>, t: Throwable) {
}
})
复制代码
Retrofit原理分析
网络通信八大步骤
Retrofit类的构建
Retrofit类中七大成员变量
serviceMethodCache
是Map类型数据key值Method
是Http请求方法,value是ServiceMethod
是解析网络请求接口后的对象,与注解中的Get
、Put
是成对出现的,缓存网络请求信息的对象,用于缓存网络请求方法与配置、数据转换器、网络请求适配器等等callFactory
用于生产okhttpClientbaseUrl
网络请求基地址与接口中的相对地址拼接起来就是完整的网络地址converterFactories
数据转换器工厂集合,数据转换就是把网路请求得Reponse
转换成Java
对象callAdapterFactories
网络请求适配器工厂集合,网络请求适配器就是把Call对象转换成其它类型。例如想执行Rxjava时候就转化成Rxjava得call对象callbackExecutor
用于执行回调,处理异步网络请求validateEagerly
是一标志位,表示是否立即解析接口中方法
Retrofit中Builder
类
- 表示Retrofit的创建是构造者模式
- 成员变量
-
platform
表示Retrofit适配的平台,例如Android、java8、ios等
-
callFactory
表示请求网络的okhttp工厂,默认情况下是okhttpClient
-
baseUrl
网络请求url地址
-
converterFactories
数据转换器工厂
-
callAdapterFactrories
网络请求适配器集合
-
callbackExecutor
用于执行异步回调,在Android中默认执行主线程Executor
-
validateEagerly
标志位,表示是否立即解析接口中方法,在动态代理中会用到
- 成员变量除了
platform
与serviceMethodCache
不同外,Retrofit.Builder
成员变量与Retrofit
大体相同
Platform
对象是一个单例,通过反射findPlatform()
查找当加载指定类,返回Android
对象表示使用Android平台
-
- 在
Android
对象中,defaultCallbackExecutor()
方法返回一默认的回调方法执行器,用于从子线程切换到主线程,同时可以在主线程中执行回调方法
- 在
-
-
MainThreadExecutor
类中new Handler(Looper.getMainLooper())
也证明了与主线程进行绑定
-
-
- 由于当前
Android
对象是继承Platform
,因此默认网络请求适配器方法由于Platform
中的defaultCallAdapterFactories
方法获得
- 由于当前
- 相对于无参构造,
Builder
的有参构造有两个,一个人是用于赋值给Builder
中的platform
,另一个在platform
参数。另外一个在platform
参数上的处理是一样的,其它主要参数使用传入retrofit
的参数进行赋值
- 注意目前
Builder
的各参数只是默认值的初始化,并没有进行具体的配置,没有正在配置到Retrofit的成员变量中
Retrofit类中baseUrl()
方法
- 首先进行工具类判断传入参数是否为空
- 然后将
String
类型的Url
转为HttpUrl
类型的Url
- 然后对路径列表
pathSegments
进行赋值,主要将Http的Url拆分成多个独立碎片 - 判断http地址最后是否以斜杠结尾否则抛出异常
- 最后对
baseUrl
进行赋值并返回当前Builder
(便于后面链式调用)
Retrofit类中addConverterFactory()
方法
- 这个方法主要把当前对象添加到
converterFactories
数据转换器工厂集合中
GsonConverterFactory
主要功能是运用工厂模式创建含有json对象的GsonConverterFactory
类
Retrofit类中addCallAdapterFactory()
方法
- 这个方法主要把当前对象添加到
callAdapterFactories
网络请求适配器工厂集合中
RxJava2CallAdapterFactory.create()
作用是创建含有scheduler
调度器的RxJava2CallAdapterFactory
对象- 将Retrofit中的Call对象封装成java对象
- 这里先简要说明,在
Rxjava2CallAdapter
中的adapt
方法中的observable.subscribeOn(scheduler)
表示在订阅关系建立后进行了网络请求
Retrofit类中build()
方法
- 首先进行了baseUrl的非空判断
callFactory
为空情况下,创建OkHttpClient()
对象并赋值给callFactory
- 初始化回调方法执行器
callbackExecutor
,在空的情况下会调用上面我们研究过的platform
类中的platform.defaultCallbackExecutor()
进行配置 - 复制网络请求适配器工厂集合
callAdapterFactories
并添加平台默认callAdapter
- 创建数据转换器工厂集合副本
converterFactories
并添加原来说有converterFactories
、平台默认数据转换器、内置数据转换器工厂BuiltInConverters
(Retrofit内部默认指定提供的) - 最后把以上成员变量传到
new Retrofit()
中进行对象创建
创建网络接口实例
代码流程
- 在使用过程中,我们先定义接口
- 这里主要的是
@GET
注解中可以是全路径,那么就可以不设置baseUrl()
interface MyInterface {
@GET(".../...")
Call<List<String>> getCall();
}
复制代码
- 然后调用创建好的
retrofit
对象中的create()
方法 - 这里采用了外观模式与动态代理模式
var myInterface = retrofit.create(MyInterface::class.java)
复制代码
retrofit.create()方法分析
- 首先
validateServiceInterface()
是对我们传进来的字节码进行验证 - 然后我们可以看到之前的标志位
validateEagerly
这理接下来的逻辑表示我们是否要提前验证接口,是否需要提前解析接口 -
- 这里的实现为首先获取具体平台
-
- 然后通过反射获取我们传递对象的方法
-
- 遍历接口中的方法
-
- 满足判断条件后调用
loadServiceMethod(method)
- 满足判断条件后调用
-
-
- 在
loadServiceMethod()
中有一个很重要的对象ServiceMethod
,它是我们定义的接口方法Call
通过动态代理封装转化而来的,一个ServiceMethod
对应一个接口方法Call
- 在
-
-
-
- 然后不会直接创建
ServiceMethod
,从缓存池中取,采用线程同步锁 来锁住serviceMethodCache
- 然后不会直接创建
-
-
-
- 如果通过
serviceMethodCache.get(method)
获取到的result
不为空,则返回result
。若result
为空,则创建一个ServiceMethod
(构建者模式),最后把创建好后result
保存到serviceMethodCache
中
- 如果通过
-
-
-
- 最终会返回
ServiceMethod
对象
- 最终会返回
-
- 回过头来看
create
方法,从Proxy.newProxyInstance
可以看出,该方法return
是一个网路请求接口的动态代理对象 - 对于
Proxy.newProxyInstance
这个方法,我们会传进来一个Class
对象(new Class<?>[] {service}
)然后生成一个实例,这个实例代表我们的代理类,每当执行代理类中的方法时候就会调用InvocationHandler
中的invoke
方法,这里的invoke
是真正做接口解析的工作 - 由于我们是在Android平台上使用的,因此不会走到if判断中,那么主要的就是运行
loadServiceMethod(method).invoke(args)
loadServiceMethod(method)
方法是我们之前已经分析过的用来加载ServiceMethod
的,对应我们接口中的网路请求方法- 在
ServiceMethod
里,通过RequestFactory.parseAnnotations
方法(构建者模式)加载各网络数据以及解析注解,包含了各网路请求参数以及parameterHandlers
(方法参数处理器,解析方法与方法上注解) ServiceMethod
通过HttpServiceMethod.parseAnnotations
方法来加载网络请求适配器以及数据转换设配器等
loadServiceMethod(method).invoke(args)
中的invoke
方法,创建了call
的实现类OkhttpCall
并返回了adapt
方法
OkHttpCall
requestFactory
请求信息工作包含http各成员变量args
一个包含网络接口请求参数的数组callFactory
用于生产okhttpClientrawCall
实际进行网络请求的类,就是okhttp
原生的call
responseConverter
网络响应后数据转换器canceled
为状态标志位,在网络请求时判断是否取消call
creationFailure
表示构建OkHttpCall
时后产生哪些异常要进行处理executed
异步请求时用于判断的标志位- 总的来说
OkHttpCall
就是Retrofit
封装好的okhttp
库中的call
对象,无论同步还是异步网络请求都是调用call
对象方法
- 分析完
OkHttpCall
的创建后,回到invoke
方法方法中可以发现,把创建好的OkHttpCall
传进了callAdapter.adapt
方法进行适配 - 这里的
callAdapter
是通过loadServiceMethod(method)
方法加载出来的ServiceMethod
类中的callAdapter
- 这样做的目的是为了适配各平台的
call
(适配器模式)
动态代理生产请求对象call
retrofit.create(MyInterface::class.java)
这个方法被调用时,我们获取到了网络请求的接口myInterface
,然后拿接口myInterface
去调用getCall()
,就好像变得很奇怪了,因为接口不能调用方法。因此这里是使用了动态代理模式,调用了Proxy.newProxyInstance
方法进行拦截,调用其InvocationHandler()
中的invoke
方法来进行实际操作,最后返回适配好的okhttpcall
类的call
对象来进行实际网络请求- 因此
myInterface.getCall()
进行的网络请求实际是动态代理返回的call
进行的网络请求,实质是通过okhttp
库进行同步或异步网络请求
Retrofit同步请求
- 主要流程
- 执行
call.execute()
表示进行同步请求,进入源码发现,在OkHttpCall
实现类中定义了okhttp3.Call
对象,再次说明了最后的实现都是通过okhttp
库来实现 - 通过
OkHttpCall
中的createRawCall()
来创建call
requestFactory.create(args)
方法是用来解析创建Request对象的- 可以看到里面有
parameterHandlers
对象解析参数
- 在创建好
Request
对象后调用callFactory.newCall(requestFactory.create(args))
实质上是调用了OkHttpClient
中的RealCall
,后面的工作就转交给Okhttp
- 回到
execute()
方法中,接下来就是判断canceled
标志位来是否取消call
- 最返回
parseResponse(call.execute())
,其中call.execute()
主要是okhttp
的内容,parseResponse
的作用是解析同步请求回来的Reponse
- 在
parseResponse
方法中,主要通过rawResponse.code()
来获取状态码code
进行相应的相应处理 responseConverter.convert(catchingBody)
是关键的一步,作用是将返回的信息通过数据转换器转换成java
对象。此时我们默认使用的是json
,因此这就将json
数据转换成java
对象- 最后将成功的
Reponse
返回
Retrofit异步请求
-
异步请求与同步请求大致一样,在
enqueue
方法中也定义了,okhttp3.Call
对象,也同样是调用createRawCall()
方法创建Call
-
在同步请求中调用的是
call.execute()
方法,返回的结果交由parseResponse(call.execute())
方法处理,在异步请求中调用的是call.enqueue(new okhttp3.Callback() {...})
方法
- 接下来同样使用
parseResponse(rawResponse)
进行数据解析 - 最后成功时调用
callback.onResponse(OkHttpCall.this, response)
进行成功处理,然后我们就可以处理整个网络请求回来的结果了 - 由此可见在Retrofit中同步与异步逻辑流程差别不是很大,Retrofit的作用就是封装
okhttp
库,通过动态代理让我们可以使用接口和我注解方便地进行网路请求