前言
- 在
Andrroid
开发中,网络请求十分常用 - 而在
Android
网络请求库中,Retrofit
是当下最热的一个网络请求库
- 今天,我将手把手带你深入剖析
Retrofit v2.0
的源码,希望你们会喜欢
在阅读本文前,建议先阅读文章:这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解)
目录
1. 简介
特别注意:
- 准确来说,Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。
- 原因:网络请求的工作本质上是
OkHttp
完成,而 Retrofit 仅负责 网络请求接口的封装
- App应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之后由 OkHttp 完成后续的请求操作
- 在服务端返回数据之后,OkHttp 将原始的结果交给 Retrofit,Retrofit根据用户的需求对结果进行解析
2. 与其他网络请求开源库对比
除了Retrofit,如今Android中主流的网络请求框架有:
- Android-Async-Http
- Volley
- OkHttp
下面是简单介绍:
一图让你了解全部的网络请求库和他们之间的区别!
附:各个主流网络请求库的Github地址
3. Retrofit 的具体使用
具体请看我写的文章:这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解)
4. 源码分析
4.1 Retrofit的本质流程
一般从网络通信过程如下图:
- 其实Retrofit的本质和上面是一样的套路
- 只是Retrofit通过使用大量的设计模式进行功能模块的解耦,使得上面的过程进行得更加简单 & 流畅
如下图:
具体过程解释如下:
- 通过解析 网络请求接口的注解 配置 网络请求参数
- 通过 动态代理 生成 网络请求对象
-
通过 网络请求适配器 将 网络请求对象 进行平台适配
平台包括:Android、Rxjava、Guava和java8
-
通过 网络请求执行器 发送网络请求
- 通过 数据转换器 解析服务器返回的数据
- 通过 回调执行器 切换线程(子线程 ->>主线程)
- 用户在主线程处理返回结果
下面介绍上面提到的几个角色
特别注意:因下面的 源码分析 是根据 使用步骤 逐步带你debug进去的,所以必须先看文章这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解)
4.2 源码分析
先来回忆Retrofit的使用步骤:
1. 创建Retrofit实例
2. 创建 网络请求接口实例 并 配置网络请求参数
3. 发送网络请求
封装了 数据转换、线程切换的操作
4. 处理服务器返回的数据
4.2.1 创建Retrofit实例
a. 使用步骤
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
b. 源码分析
Retrofit实例是使用建造者模式通过Builder类进行创建的
建造者模式:将一个复杂对象的构建与表示分离,使得用户在不知道对象的创建细节情况下就可以直接创建复杂的对象。具体请看文章:建造者模式(Builder Pattern)- 最易懂的设计模式解析
接下来,我将分五个步骤对创建Retrofit实例进行逐步分析
步骤1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
成功建立一个Retrofit对象的标准:配置好Retrofit类里的成员变量,即配置好:
serviceMethod
:包含所有网络请求信息的对象baseUrl
:网络请求的url地址callFactory
:网络请求工厂adapterFactories
:网络请求适配器工厂的集合converterFactories
:数据转换器工厂的集合callbackExecutor
:回调方法执行器
所谓xxxFactory
、“xxx工厂”其实是设计模式中工厂模式的体现:将“类实例化的操作”与“使用对象的操作”分开,使得使用者不用知道具体参数就可以实例化出所需要的“产品”类。
具体请看我写的文章
简单工厂模式(SimpleFactoryPattern)- 最易懂的设计模式解析
工厂方法模式(Factory Method)- 最易懂的设计模式解析
抽象工厂模式(Abstract Factory)- 最易懂的设计模式解析
这里详细介绍一下:CallAdapterFactory
:该Factory
生产的是CallAdapter
,那么CallAdapter
又是什么呢?
CallAdapter
详细介绍
-
定义:网络请求执行器(Call)的适配器
- Call在Retrofit里默认是
OkHttpCall
- 在Retrofit中提供了四种CallAdapterFactory: ExecutorCallAdapterFactory(默认)、GuavaCallAdapterFactory、Java8CallAdapterFactory、RxJavaCallAdapterFactory
- Call在Retrofit里默认是
-
作用:将默认的网络请求执行器(OkHttpCall)转换成适合被不同平台来调用的网络请求执行器形式
- 如:一开始
Retrofit
只打算利用OkHttpCall
通过ExecutorCallbackCall
切换线程;但后来发现使用Rxjava
更加方便(不需要Handler来切换线程)。想要实现Rxjava
的情况,那就得使用RxJavaCallAdapterFactoryCallAdapter
将OkHttpCall
转换成Rxjava(Scheduler)
:
- 如:一开始
- 1
- 2
- 3
- 1
- 2
- 3
- Retrofit还支持java8、Guava平台。
- 好处:用最小代价兼容更多平台,即能适配更多的使用场景
所以,接下来需要分析的步骤2、步骤3、步骤4、步骤4的目的是配置好上述所有成员变量
步骤2
我们先来看Builder类
请按下面提示的步骤进行查看
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
对Builder类分析完毕,总结:Builder设置了默认的
- 平台类型对象:Android
-
网络请求适配器工厂:CallAdapterFactory
CallAdapter用于对原始Call进行再次封装,如Call到Observable
-
数据转换器工厂: converterFactory
- 回调执行器:callbackExecutor
特别注意,这里只是设置了默认值,但未真正配置到具体的Retrofit类的成员变量当中
步骤3
还是按部就班按步骤来观看
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 至此,步骤3分析完毕
- 总结:baseUrl()用于配置Retrofit类的网络请求url地址
将传入的String类型url转化为适合OKhttp的HttpUrl类型的url
步骤4
我们从里往外看,即先看GsonConverterFactory.creat()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 所以,GsonConverterFactory.creat()是创建了一个含有Gson对象实例的GsonConverterFactory,并返回给
addConverterFactory()
- 接下来继续看:
addConverterFactory()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 至此,分析完毕
- 总结:步骤4用于创建一个含有Gson对象实例的GsonConverterFactory并放入到数据转换器工厂converterFactories里
- 即Retrofit默认使用Gson进行解析
- 若使用其他解析方式(如Json、XML或Protocobuf),也可通过自定义数据解析器来实现(必须继承 Converter.Factory)
- 即Retrofit默认使用Gson进行解析
步骤5
终于到了最后一个步骤了。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 至此,步骤5分析完毕
- 总结:在最后一步中,通过前面步骤设置的变量,将Retrofit类的所有成员变量都配置完毕。
- 所以,成功创建了Retrofit的实例
总结
Retrofit 使用建造者模式通过Builder类建立了一个Retrofit实例,具体创建细节是配置了:
- 平台类型对象(Platform - Android)
- 网络请求的url地址(baseUrl)
-
网络请求工厂(callFactory)
默认使用OkHttpCall
-
网络请求适配器工厂的集合(adapterFactories)
本质是配置了网络请求适配器工厂- 默认是ExecutorCallAdapterFactory
- 数据转换器工厂的集合(converterFactories)
本质是配置了数据转换器工厂
- 回调方法执行器(callbackExecutor)
默认回调方法执行器作用是:切换线程(子线程 - 主线程)
由于使用了建造者模式,所以开发者并不需要关心配置细节就可以创建好Retrofit实例,建造者模式get。在创建Retrofit对象时,你可以通过更多更灵活的方式去处理你的需求,如使用不同的Converter、使用不同的CallAdapter,这也就提供了你使用RxJava来调用Retrofit的可能
2. 创建网络请求接口的实例
2.1 使用步骤
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
2.2 源码分析
- 结论:Retrofit是通过外观模式 & 代理模式 使用create()方法创建网络请求接口的实例(同时,通过网络请求接口里设置的注解进行了网络请求参数的配置)
- 外观模式:定义一个统一接口,外部与通过该统一的接口对子系统里的其他接口进行访问。具体请看:外观模式(Facade Pattern) - 最易懂的设计模式解析
- 代理模式:通过访问代理对象的方式来间接访问目标对象。具体请看:代理模式(Proxy Pattern)- 最易懂的设计模式解析
- 下面主要分析步骤3和步骤4:
- 外观模式:定义一个统一接口,外部与通过该统一的接口对子系统里的其他接口进行访问。具体请看:外观模式(Facade Pattern) - 最易懂的设计模式解析
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
步骤3讲解:
AccessApi NetService = retrofit.create(NetService.class);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
使用外观模式进行访问,里面用了代理模式
1. 外观模式
-
外观模式:定义一个统一接口,外部与通过该统一的接口对子系统里的其他接口进行访问。具体请看:外观模式(Facade Pattern) - 最易懂的设计模式解析
-
Retrofit对象的外观(门店) =
retrofit.create()
- 通过这一外观方法就可以在内部调用各个方法创建网络请求接口的实例和配置网络请求参数
大大降低了系统的耦合度
2. 代理模式
- 代理模式:通过访问代理对象的方式来间接访问目标对象
分为静态代理 & 动态代理:
1. 静态代理:代理类在程序运行前已经存在的代理方式
2. 动态代理:代理类在程序运行前不存在、运行时由程序动态生成的代理方式
具体请看文章代理模式(Proxy Pattern)- 最易懂的设计模式解析 return (T) roxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler)
通过代理模式中的动态代理模式,动态生成网络请求接口的代理类,并将代理类的实例创建交给InvocationHandler类
作为具体的实现,并最终返回一个动态代理对象。
生成实例过程中含有生成实现类的缓存机制(单例模式),下面会详细分析
使用动态代理的好处:- 当
NetService
对象调用getCall()
接口中方法时会进行拦截,调用都会集中转发到 InvocationHandler#invoke (),可集中进行处理 - 获得网络请求接口实例上的所有注解
- 更方便封装ServiceMethod
下面看源码分析
下面将详细分析`InvocationHandler类 # invoke()`里的具体实现- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
关注点1:
ServiceMethod serviceMethod = loadServiceMethod(method);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
下面,我将分3个步骤详细分析
serviceMethod
实例的创建过程:
步骤1:
ServiceMethod类
构造函数- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
步骤2:
ServiceMethod的Builder()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
步骤3:
ServiceMethod的build()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 当选择了RxjavaCallAdapterFactory后,Rxjava通过策略模式选择对应的adapter
关于策略模式的讲解,请看文章 策略模式(Strategy Pattern)- 最易懂的设计模式解析
- 具体过程是:根据网络接口方法的返回值类型来选择具体要用哪种CallAdapterFactory,然后创建具体的CallAdapter实例
采用工厂模式使得各功能模块高度解耦
- 上面提到了两种工厂:CallAdapter.Factory & Converter.Factory分别负责提供不同的功能模块
- 工厂负责如何提供、提供何种功能模块
- Retrofit 只负责提供选择何种工厂的决策信息(如网络接口方法的参数、返回值类型、注解等)
这正是所谓的高内聚低耦合,工厂模式get。
关于工厂模式请看我写的文章:
简单工厂模式(SimpleFactoryPattern)- 最易懂的设计模式解析
工厂方法模式(Factory Method)- 最易懂的设计模式解析
抽象工厂模式(Abstract Factory)- 最易懂的设计模式解析终于配置完网络请求参数(即配置好
ServiceMethod
对象)。接下来将讲解第二行代码:okHttpCall对象
的创建第二行:
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
根据第一步配置好的
ServiceMethod
对象和输入的请求参数创建okHttpCall
对象- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
第三行:
return serviceMethod.callAdapter.adapt(okHttpCall);
将第二步创建的
OkHttpCall
对象传给第一步创建的serviceMethod
对象中对应的网络请求适配器工厂的adapt()
返回对象类型:Android默认的是
Call<>
;若设置了RxJavaCallAdapterFactory,返回的则是Observable<>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 采用了装饰模式:ExecutorCallbackCall = 装饰者,而里面真正去执行网络请求的还是OkHttpCall
- 使用装饰模式的原因:希望在OkHttpCall发送请求时做一些额外操作。这里的额外操作是线程转换,即将子线程切换到主线程
- OkHttpCall的enqueue()是进行网络异步请求的:当你调用OkHttpCall.enqueue()时,回调的callback是在子线程中,需要通过Handler转换到主线程进行回调。ExecutorCallbackCall就是用于线程回调;
- 当然以上是原生Retrofit使用的切换线程方式。如果你用Rxjava,那就不会用到这个ExecutorCallbackCall而是RxJava的Call,此处不过多展开
- OkHttpCall的enqueue()是进行网络异步请求的:当你调用OkHttpCall.enqueue()时,回调的callback是在子线程中,需要通过Handler转换到主线程进行回调。ExecutorCallbackCall就是用于线程回调;
步骤4讲解:
Call<JavaBean> call = NetService.getCall();
NetService
对象实际上是动态代理对象Proxy.newProxyInstance()
(步骤3中已说明),并不是真正的网络请求接口创建的对象- 当
NetService
对象调用getCall()
时会被动态代理对象Proxy.newProxyInstance()
拦截,然后调用自身的InvocationHandler # invoke()
invoke(Object proxy, Method method, Object... args)
会传入3个参数:Object proxy:
(代理对象)、
Method method
(调用的getCall()
)
Object... args
(方法的参数,即getCall(*)
中的*)- 接下来利用Java反射获取到
getCall()
的注解信息,配合args参数创建ServiceMethod对象
。
如上面步骤3描述,此处不再次讲解
最终创建并返回一个OkHttpCall
类型的Call对象
1.OkHttpCall
类是OkHttp
的包装类
2. 创建了OkHttpCall
类型的Call对象还不能发送网络请求,需要创建Request
对象才能发送网络请求总结
Retrofit采用了 外观模式 统一调用创建网络请求接口实例和网络请求参数配置的方法,具体细节是:
- 动态创建网络请求接口的实例(代理模式 - 动态代理)
- 创建
serviceMethod
对象(建造者模式 & 单例模式(缓存机制)) - 对
serviceMethod
对象进行网络请求参数配置:通过解析网络请求接口方法的参数、返回值和注解类型,从Retrofit对象中获取对应的网络请求的url地址、网络请求执行器、网络请求适配器 & 数据转换器。(策略模式) - 对
serviceMethod
对象加入线程切换的操作,便于接收数据后通过Handler从子线程切换到主线程从而对返回数据结果进行处理(装饰模式) - 最终创建并返回一个
OkHttpCall
类型的网络请求对象
3. 执行网络请求
Retrofit
默认使用OkHttp
,即OkHttpCall类
(实现了retrofit2.Call<T>
接口)
但可以自定义选择自己需要的Call类
OkHttpCall
提供了两种网络请求方式:
- 同步请求:
OkHttpCall.execute()
- 异步请求:
OkHttpCall.enqueue()
- 同步请求:
下面将详细介绍这两种网络请求方式。
对于OkHttpCall的enqueue()、execute()此处不往下分析,有兴趣的读者可以看OkHttp的源码3.1 同步请求
OkHttpCall.execute()
3.1.1 发送请求过程
- 步骤1:对网络请求接口的方法中的每个参数利用对应
ParameterHandler
进行解析,再根据ServiceMethod
对象创建一个OkHttp
的Request
对象 - 步骤2:使用
OkHttp
的Request
发送网络请求; - 步骤3:对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的数据,最终得到一个
Response<T>
对象
3.1.2 具体使用
- 1
- 1
上面简单的一行代码,其实包含了整个发送网络同步请求的三个步骤。
3.1.3 源码分析
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
特别注意:
ServiceMethod
几乎保存了一个网络请求所需要的数据- 发送网络请求时,
OkHttpCall
需要从ServiceMethod
中获得一个Request对象 -
解析数据时,还需要通过
ServiceMethod
使用Converter
(数据转换器)转换成Java对象进行数据解析为了提高效率,Retrofit还会对解析过的请求
ServiceMethod
进行缓存,存放在Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
对象中,即第二步提到的单例模式 -
关于状态码检查时的状态码说明:
以上便是整个以同步的方式发送网络请求的过程。
3.2 异步请求
OkHttpCall.enqueue()
3.2.1 发送请求过程
- 步骤1:对网络请求接口的方法中的每个参数利用对应
ParameterHandler
进行解析,再根据ServiceMethod
对象创建一个OkHttp
的Request
对象 - 步骤2:使用
OkHttp
的Request
发送网络请求; - 步骤3:对返回的数据使用之前设置的数据转换器(GsonConverterFactory)解析返回的数据,最终得到一个
Response<T>
对象 - 步骤4:进行线程切换从而在主线程处理返回的数据结果
若使用了RxJava,则直接回调到主线程
异步请求的过程跟同步请求类似,唯一不同之处在于:异步请求会将回调方法交给回调执行器在指定的线程中执行。
指定的线程此处是指主线程(UI线程)3.2.2 具体使用
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 从上面分析有:
call
是一个静态代理 - 使用静态代理的作用是:在okhttpCall发送网络请求的前后进行额外操作
这里的额外操作是:线程切换,即将子线程切换到主线程,从而在主线程对返回的数据结果进行处理
3.2.3 源码分析
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
以上便是整个以 异步方式发送网络请求的过程。
5. 总结
Retrofit
本质上是一个RESTful
的HTTP
网络请求框架的封装,即通过 大量的设计模式 封装了OkHttp
,使得简洁易用。具体过程如下:Retrofit
将Http
请求 抽象 成Java
接口- 在接口里用 注解 描述和配置 网络请求参数
- 用动态代理 的方式,动态将网络请求接口的注解 解析 成
HTTP
请求 - 最后执行
HTTP
请求
最后贴一张非常详细的
Retrofit
源码分析图:6. 最后
- 看完本文,相信你已经非常熟悉
Retrofit 2.0
的源码分析 - 关于
Retrofit 2.0
的详细使用教程,请看文章这是一份很详细的 Retrofit 2.0 使用教程(含实例讲解) - 接下来,我将继续分析与 Retrofit 配合使用的 RxJava,有兴趣可以继续关注Carson_Ho的安卓开发笔记