Learn && Live
虚度年华浮萍于世,勤学善思至死不渝
前言
Hey,欢迎阅读Connor学Android系列,这个系列记录了我的Android原理知识学习、复盘过程,欢迎各位大佬阅读斧正!原创不易,转载请注明出处:http://t.csdn.cn/EVHjI,话不多说我们马上开始!
1.使用
异步GET请求
(1)创建OkHttpClient对象
(2)通过Builder模式创建Request对象,参数必须有个url参数,可以通过Request.Builder设置更多的参数比如:header、method等
(3)通过request的对象去构造得到一个Call对象,Call对象有execute()和cancel()等方法。
(4)以异步的方式去执行请求,调用的是call.enqueue,将call加入调度队列,任务执行完成会在Callback中得到结果。
注意事项:
- 异步调用的回调函数是在子线程,我们不能在子线程更新UI
- onResponse回调有一个参数是response
- 如果想获得返回的是字符串,可以通过response.body().string()
- 如果获得返回的二进制字节数组,则调用response.body().bytes()
- 如果想拿到返回的inputStream,则调response.body().byteStream(),之后通过IO的方式写文件
异步POST请求
与GET类似,只是需要传输实体
通过FormBody,添加多个String键值对,最后为Request添加post方法并传入formBody
2.基本对象介绍
OkHttpClient
创建 OkHttpClient 有两种方式:new 或 使用建造者模式为其设置一些参数,无论哪一种,实际上都是使用建造者模式完成的
open class OkHttpClient internal constructor(builder: Builder)
: Cloneable, Call.Factory, WebSocket.Factory {
constructor() : this(Builder())
class Builder constructor() {
//调度器
internal var dispatcher: Dispatcher = Dispatcher()
//连接池
internal var connectionPool: ConnectionPool = ConnectionPool()
//整体流程拦截器
internal val interceptors: MutableList<Interceptor> = mutableListOf()
//网络流程拦截器
internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
//流程监听器
internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
//连接失败时是否重连
internal var retryOnConnectionFailure = true
//服务器认证设置
internal var authenticator: Authenticator = Authenticator.NONE
//是否重定向
internal var followRedirects = true
//是否从HTTP重定向到HTTPS
internal var followSslRedirects = true
//cookie设置
internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
//缓存设置
internal var cache: Cache? = null
//DNS设置
internal var dns: Dns = Dns.SYSTEM
//代理设置
internal var proxy: Proxy? = null
//代理选择器设置
internal var proxySelector: ProxySelector? = null
//代理服务器认证设置
internal var proxyAuthenticator: Authenticator = Authenticator.NONE
//socket配置
internal var socketFactory: SocketFactory = SocketFactory.getDefault()
//https socket配置
internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
internal var x509TrustManagerOrNull: X509TrustManager? = null
internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
//协议
internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS
//域名校验
internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
internal var certificateChainCleaner: CertificateChainCleaner? = null
//请求超时
internal var callTimeout = 0
//连接超时
internal var connectTimeout = 10_000
//读取超时
internal var readTimeout = 10_000
//写入超时
internal var writeTimeout = 10_000
internal var pingInterval = 0
internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
internal var routeDatabase: RouteDatabase? = null
}
}
Request
同样是请求参数的配置类,也同样采用了建造者模式,但相比于OkHttpClient
,Request
就十分简单了,只有四个参数,分别是请求URL、请求方法、请求头、请求体
class Request internal constructor(
@get:JvmName("url") val url: HttpUrl,
@get:JvmName("method") val method: String,
@get:JvmName("headers") val headers: Headers,
@get:JvmName("body") val body: RequestBody?,
internal val tags: Map<Class<*>, Any>
) {
open class Builder {
//请求的URL
internal var url: HttpUrl? = null
//请求方法,如:GET、POST..
internal var method: String
//请求头
internal var headers: Headers.Builder
//请求体
internal var body: RequestBody? = null
}
}
Call
请求调用接口,针对请求提供了一系列的操作方法,常见的有
- request():返回 Request 对象
- execute():同步请求,立即执行,请求失败抛出 IOException、执行过一次后再次执行抛出 IllegalStateException
- enqueue():异步请求,将请求安排在将来某个时间点执行,若执行过一次后再次执行抛出 IllegalStateException
- cancel():取消请求,注意已经完成的请求不能被取消
- 利用工厂模式来让 OkHttpClient 、Request 对象来创建 newCall 对象
interface Call : Cloneable {
/** 返回发起此调用的原始请求 */
fun request(): Request
/**
* 同步请求,立即执行。
*
* 抛出两种异常:
* 1. 请求失败抛出IOException;
* 2. 如果在执行过一回的前提下再次执行抛出IllegalStateException;*/
@Throws(IOException::class)
fun execute(): Response
/**
* 异步请求,将请求安排在将来的某个时间点执行。
* 如果在执行过一回的前提下再次执行抛出IllegalStateException */
fun enqueue(responseCallback: Callback)
/** 取消请求。已经完成的请求不能被取消 */
fun cancel()
/** 是否已被执行 */
fun isExecuted(): Boolean
/** 是否被取消 */
fun isCanceled(): Boolean
/** 一个完整Call请求流程的超时时间配置,默认选自[OkHttpClient.Builder.callTimeout] */
fun timeout(): Timeout
/** 克隆这个call,创建一个新的相同的Call */
public override fun clone(): Call
/** 利用工厂模式来让 OkHttpClient 来创建 Call对象 */
fun interface Factory {
fun newCall(request: Request): Call
}
}
RealCall
(1)在使用时,通过 OkHttpClient 的 newCall() 方法创建一个 Call 对象,通过源码知道,newCall() 方法返回的是一个 RealCall 对象
(2)RealCall 是 Call 接口的实现类,内部有三个参数:OkHttpClient、Request、是否使用 WebSocket(默认为 false)
(3)RealCall 实现了上述 Call 接口的方法,因此可以调用 execute() 和 enqueue() 方法完成同步或异步请求方法
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
AsyncCall
(1)是 RealCall 的一个内部类,它继承自 NamedRunnable,NamedRunnable 实现了 Runnable 接口,它的作用有两个:
-
采用模板方法的设计模式,让子类将具体的操作放在 execute() 方法中
-
给线程指定一个名字,比如传入模块名称,方便监控线程的活动状态
(2)AsyncCall 实现了 execute() 方法,用于异步请求下的调用,后续的流程分析会做详细介绍
Dispatcher
(1)调度器,用于调度 Call 对象
(2)内部包含
-
最大任务请求数限制,不可大于64
-
ThreadPoolExecutor 作为默认线程池,也可以通过构造方法执行其他线程池
-
ArrayDeque 类型的 readyAsyncCalls 已准备好的异步请求队列
-
ArrayDeque 类型的 runningAsyncCalls 正在运行的异步请求队列,包含取消但是还未 finish 的 AsyncCall
-
ArrayDeque 类型的 runningSyncCalls 正在运行的同步请求队列,包含取消但是还未 finish 的 RealCall
class Dispatcher constructor() {
@get:Synchronized
@get:JvmName("executorService") val executorService: ExecutorService
get() {
if (executorServiceOrNull == null) {
//创建一个缓存线程池,来处理请求调用
executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
}
return executorServiceOrNull!!
}
/** 已准备好的异步请求队列 */
@get:Synchronized
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
/** 正在运行的异步请求队列, 包含取消但是还未finish的AsyncCall */
private val runningAsyncCalls = ArrayDeque<AsyncCall>()
/** 正在运行的同步请求队列, 包含取消但是还未finish的RealCall */
private val runningSyncCalls = ArrayDeque<RealCall>()
···省略代码···
}
总结
对象 | 作用 |
---|---|
Call | 请求调用接口,表示这个请求已经准备好可以执行,也可以被取消,只能执行一次 |
RealCall | Call 接口的具体实现类,是应用与网络层之间的连接桥,包含 OkHttpClient 和 Request 信息 |
AsyncCall | 异步请求调用,其实就是个 Runnable,会被放到线程池中进行处理 |
Dispatcher | 调度器,用来调度 Call 对象,同时包含线程池与异步请求队列,用来存放与执行 AsyncCall 对象 |
Request | 请求类,包含 url、method、headers、body |
Response | 网络层返回的响应数据 |
Callback | 响应回调函数接口,包含 onFailure 、onResponse 两个方法 |
3.异步请求流程分析
(1)异步请求首先会调用 RealCall 的 enqueue() 方法,这个方法内会做两件事
- 检查是否重复调用了 enqueue() 方法
- 调用 Dispatcher 的 enqueue() 方法,并将 AsyncCall 传进去
(2)Dispatcher 的 enqueue() 方法内会将传入的 AsyncCall 加入 Dispatcher 的 ready 队列中,并调用 promoteAndExecutor() 方法
(3)promoteAndExecutor() 方法内会遍历 ready 队列,取出每个 AsyncCall,并对当前的运行状态做双重约束
- running 队列中的个数不可以超出最大请求数,若不满足则直接退出遍历循环,直至 running 队列有空位
- AsyncCall 中的主机数不可以超出同一主机的最大任务数,若不满足则遍历下一个 AsyncCall
若满足则将当前的 AsyncCall 添加到 running 队列中,并调用 AsyncCall 的 executeOn 方法
(4)executeOn 方法中主要做三件事
- 将当前遍历到的 AsyncCall 添加到线程池 executorService 中,调用 execute() 方法执行异步任务
- 通过拦截器链来得到网络响应
- 无论相应成功还是失败,都会调用 Dispatcher 中的 finished 方法
(5)finished() 方法内主要做两件事
- 将已执行完的 AsyncCall 退出 running 队列
- 继续调用 promoteAndExecute() 方法遍历 ready 队列中的下一个 AsyncCall,形成完美闭环
拦截器链
(1)AsyncCall 的 executeOn() 方法中会通过拦截器链来得到网络相应,这里调用的是 getResponseWithInterceptorChain() 方法
(2)这个方法主要做了两件事:
- 创建拦截器集合,并将所有的拦截器
- 创建职责链,并调用 proceed() 方法启动
- 职责链采用的是职责链模式,使得每一个拦截器都有机会处理请求
- 网络请求经过拦截器链的处理发送
- 响应也会经过拦截器链的处理返回给应用层
- proceed() 内会调用 RealInterceptorChain 的 copy() 方法,其内部会创建一个 RealInterceptorChain ,并循环处理每个拦截器
- 首先获取当前要执行的拦截器
- 运行当前拦截器,等当前拦截器处理完成后,会接着执行下一个拦截器的 proceed
- 职责链采用的是职责链模式,使得每一个拦截器都有机会处理请求
(3)各个拦截器的作用
- interceptor:应用拦截器,通过 Client 设置
- RetryAndFollowUpInterceptor:重试拦截器,负责网络请求中的重试和重定向。比如网络请求过程中出现异常时重试请求
- BridgeInterceptor:桥接拦截器,用于桥接应用层和网络层的数据。请求时将应用层的数据类型转换为网络层的数据类型,响应时则相反
- CacheInterceptor:缓存拦截器,负责读取和更新缓存。可以配置自定义的缓存拦截器
- ConnectInterceptor:网络连接拦截器,其内部会获取一个连接
- networkInterceptor:网络拦截器,通过 Client 设置
- CallServerInterceptor:请求服务拦截器。拦截链中位于末尾的拦截器,用于向服务端发送数据并获取响应