HTTP是现代应用程序网络的方式。这就是我们交换数据和媒体的方式。有效地执行HTTP可以使您的内容加载更快并节省带宽。
OkHttp是一个高效的HTTP库:
- 支持HTTP / 2,允许对同一主机的所有请求共享一个套接字
- 通过连接池可减少请求延迟(如果HTTP / 2不可用)
- 支持GZIP压缩减少数据流量
- 响应缓存可以完全避免网络重复请求
- 静默恢复处理常见的连接问题
- …
本文就以请求使用为入口,来深入学习下OkHttp。
一、请求流程分析
1. 同步请求
Okhttp同步GET请求使用:
// 新建一个Okhttp客户端(也可以通过OkHttpClient.Builder来构造)
OkHttpClient client = new OkHttpClient();
// 构造一个请求对象
Request request = new Request.Builder().url(url).build();
// 执行同步请求,返回响应
Response response = client.newCall(request).execute();
// 从响应体中获取数据
String str = response.body().string();
先来瞧瞧构建OkhttpClient的源码:
open class OkHttpClient internal constructor(
builder: Builder
) : Cloneable, Call.Factory, WebSocket.Factory {
//若直接实例化OkHttpClient,则调用主构造函数以默认Builder作为参数
constructor() : this(Builder())
// 通过builder中的值赋值
@get:JvmName("dispatcher") val dispatcher: Dispatcher = builder.dispatcher
@get:JvmName("connectionPool") val connectionPool: ConnectionPool = builder.connectionPool
...
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
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
...
}
}
OkhttpClient可以通过构造者配置参数来构建,也可以直接实例化,直接实例化其实也是内部调用构造者,只是传入的是默认builder。
再来看看OkhttpClient的newCall方法
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
发现返回的是RealCall,接下来去RealCall中看后续的execute执行方法
override fun execute(): Response {
//确认call没有执行过并置executed为true,否则抛出异常
check(executed.compareAndSet(false, true)) {
"Already Executed" }
timeout.enter()
callStart()
try {
//标记执行中
client.dispatcher.executed(this)
//通过拦截器链获取网络响应
return getResponseWithInterceptorChain()
} finally {
//标记执行结束
client.dispatcher.finished(this)
}
}
看起来比较精简,通过拦截器链获取网络响应,然后返回响应(拦截器链路在后续拦截器分析)。
2. 异步请求
Okhttp异步GET请求使用:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
// 执行异步请求,通过回调返回响应
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NotNull Call call, @NotNull IOException e) {
}
@Override
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
// 从回调中通过响应体获取数据
String str = response.body().string();
}
});
异步请求流程大致和同步请求相似,但是最后的执行方法是enqueue,并传入回调对象。
我们来看看源码:
override fun enqueue(responseCallback: Callback) {
//确认call没有执行过并置executed为true,否则抛出异常
check(executed.compareAndSet(false, true)) {
"Already Executed" }
//监听回调
callStart()
//调用Dispatcher的enqueue方法,并传入一个AsyncCall对象
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
内部调用了客户端的分发器的enqueue方法,并把AsyncCall(responseCallback)作为参数传入,AsyncCall是继承自Runnable,且是RealCall的内部类,我们先看Dispatcher.enqueue()方法
class Dispatcher constructor() {
/** '异步准备执行'队列 */
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
/** '异步正在执行'队列,包括取消但至今还没结束的 */
private val runningAsyncCalls = ArrayDeque<AsyncCall>()
/** ‘同步正在执行’队列*/
private val runningSyncCalls = ArrayDeque<RealCall>()
...
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
//加入准备执行队列
readyAsyncCalls.add(call)
...
}
// 执行
promoteAndExecute()
}
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
val executableCalls = mutableListOf<AsyncCall>()
val isRunning