OkHttp探索
前言
OkHttp 是移动支付Square公司推出的一款网络请求处理框架。是Android开发使用最多最火热的一款网络请求框架,下面就OkHttp使用和源码进行探索。
OkHttp简单使用
1.添加依赖
implementation("com.squareup.okhttp3:okhttp:4.9.0")
2.初始化OkHttpClient
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.get()
.url("你的URL")
.build();
也可以
OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
okHttpClient.readTimeout(mReadTimeOut, TimeUnit.MILLISECONDS);
okHttpClient.connectTimeout(mConnectTimeOut,TimeUnit.MILLISECONDS);
okHttpClient.writeTimeout(mWriteTimeOut, TimeUnit.MILLISECONDS);
okHttpClient.build();
3.将Request封装为Call
Call call = client.okHttpClient(request);
4.发送一个同步请求
Response response = okHttpClient.newCall(request).execute();
String result = response.body().string();
5.发送一个异步请求
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String json= response.body().string();
}
});
OkHttpClient.Builder
OkHttpClient采用了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
internal var followSslRedirects = true
internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
internal var cache: Cache? = null
internal var dns: Dns = Dns.SYSTEM
internal var proxy: Proxy? = null
internal var proxySelector: ProxySelector? = null
internal var proxyAuthenticator: Authenticator = Authenticator.NONE
internal var socketFactory: SocketFactory = SocketFactory.getDefault()
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
以上代码可以看出有很多属性我们可以供我们配置,比如读写超时、失败重连等扩展性很强。
okHttpClient.newCall
/** Prepares the [request] to be executed at some point in the future. */
override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)
返回了RealCall对象,它是Call的实现类。看下RealCall
override fun execute(): Response {
check(executed.compareAndSet(false, true)) { "Already Executed" }
timeout.enter()
callStart()
try {
client.dispatcher.executed(this)
return getResponseWithInterceptorChain()
} finally {
client.dispatcher.finished(this)
}
}
override fun enqueue(responseCallback: Callback) {
check(executed.compareAndSet(false, true)) { "Already Executed" }
callStart()
client.dispatcher.enqueue(AsyncCall(responseCallback))
}
上面的核心代码getResponseWithInterceptorChain()方法是真正进行网络请求的地方。源码如下
@Throws(IOException::class)
internal fun getResponseWithInterceptorChain(): Response {
// Build a full stack of interceptors.
val interceptors = mutableListOf<Interceptor>()
interceptors += client.interceptors
interceptors += RetryAndFollowUpInterceptor(client)
interceptors += BridgeInterceptor(client.cookieJar)
interceptors += CacheInterceptor(client.cache)
interceptors += ConnectInterceptor
if (!forWebSocket) {
interceptors += client.networkInterceptors
}
interceptors += CallServerInterceptor(forWebSocket)
val chain = RealInterceptorChain(
call = this,
interceptors = interceptors,
index = 0,
exchange = null,
request = originalRequest,
connectTimeoutMillis = client.connectTimeoutMillis,
readTimeoutMillis = client.readTimeoutMillis,
writeTimeoutMillis = client.writeTimeoutMillis
)
var calledNoMoreExchanges = false
try {
val response = chain.proceed(originalRequest)
if (isCanceled()) {
response.closeQuietly()
throw IOException("Canceled")
}
return response
} catch (e: IOException) {
calledNoMoreExchanges = true
throw noMoreExchanges(e) as Throwable
} finally {
if (!calledNoMoreExchanges) {
noMoreExchanges(null)
}
}
}
请求会被交给责任链中的一个个拦截器。默认如下五个拦截器
1.RetryAndFollowUpInterceptor(重试和重定向拦截器)
第一个接触到请求,最后接触到响应(U型调用);负责判断是否需要重新发起整个请求
2.BridgeInterceptor(桥接拦截器)
补全请求,并对响应进行额外处理
3.CacheInterceptor(缓存拦截器)
请求前查询缓存,获得响应并判断是否需要缓存
4.ConnectInterceptor(链接拦截器)
与服务器完成TCP连接
5.CallServerInterceptor(请求服务拦截器)
与服务器通信;封装请求数据与解析响应数据(如:HTTP报文)
OkHttpClient.Builder的第一行代码
internal var dispatcher: Dispatcher = Dispatcher()
和同步、异步请求方法都调用了client.dispatcher,这里的dispatcher就是下面要说的Dispatcher了。
什么是Dispatcher在Okhttp中有什么作用?
Dispatcher
Dispatcher是什么?
Dispatcher的作用是维护众多请求的状态,并维护一个线程池,用于执行请求。发送的同步/异步请求都会在dispatcher中管理其状态。
/**
* The maximum number of requests to execute concurrently. Above this requests queue in memory,
* waiting for the running calls to complete.
*
* If more than [maxRequests] requests are in flight when this is invoked, those requests will
* remain in flight.
*/
@get:Synchronized var maxRequests = 64
set(maxRequests) {
require(maxRequests >= 1) { "max < 1: $maxRequests" }
synchronized(this) {
field = maxRequests
}
promoteAndExecute()
}
/**
* The maximum number of requests for each host to execute concurrently. This limits requests by
* the URL's host name. Note that concurrent requests to a single IP address may still exceed this
* limit: multiple hostnames may share an IP address or be routed through the same HTTP proxy.
*
* If more than [maxRequestsPerHost] requests are in flight when this is invoked, those requests
* will remain in flight.
*
* WebSocket connections to hosts **do not** count against this limit.
*/
@get:Synchronized var maxRequestsPerHost = 5
set(maxRequestsPerHost) {
require(maxRequestsPerHost >= 1) { "max < 1: $maxRequestsPerHost" }
synchronized(this) {
field = maxRequestsPerHost
}
promoteAndExecute()
}
/** Ready async calls in the order they'll be run. */
private val readyAsyncCalls = ArrayDeque<AsyncCall>()
/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private val runningAsyncCalls = ArrayDeque<AsyncCall>()
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private val runningSyncCalls = ArrayDeque<RealCall>()
constructor(executorService: ExecutorService) : this() {
this.executorServiceOrNull = executorService
}
1 ExecutorService线程池,用于执行请求。
2 readyAsyncCalls 异步请求的就绪队列,用于保存等待执行的请求。
3 runningAsyncCalls 异步请求的执行队列,包括已经取消(cancel)但是还没被finish掉的请求。
4 runningSyncCalls 同步请求的执行队列,包括已经取消(cancel)但是还没被finish掉的请求。
/**
* Promotes eligible calls from [readyAsyncCalls] to [runningAsyncCalls] and runs them on the
* executor service. Must not be called with synchronization because executing calls can call
* into user code.
*
* @return true if the dispatcher is currently running calls.
*/
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
val executableCalls = mutableListOf<AsyncCall>()
val isRunning: Boolean
synchronized(this) {
val i = readyAsyncCalls.iterator()
while (i.hasNext()) {
val asyncCall = i.next()
if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.
i.remove()
asyncCall.callsPerHost.incrementAndGet()
executableCalls.add(asyncCall)
runningAsyncCalls.add(asyncCall)
}
isRunning = runningCallsCount() > 0
}
for (i in 0 until executableCalls.size) {
val asyncCall = executableCalls[i]
asyncCall.executeOn(executorService)
}
return isRunning
}
1.首先判断最大请求个数是否超过了maxRequests=64个和相同host是否超过了maxRequestsPerHost=5个。
2.如果都没到最大限制,则把当前的AsyncCall从readyAsyncCalls集合中移除掉,同时对RealCall的host个数+1操作,同时加到runningAsyncCalls和executableCalls集合中。
3.最后遍历executableCalls集合,执行AsyncCall的executeOn方法,这里要注意executorService方法是返回了一个线程池。所以最后执行任务的是在asyncCall的executeOn方法。
OkHttp的优点
网络优化方面:
(1)内置连接池,支持连接复用;
(2)支持gzip压缩响应体;
(3)通过缓存避免重复的请求;
(4)支持http2,对一台机器的所有请求共享同一个socket。
功能方面:
功能全面,满足了网络请求的大部分需求
扩展性方面:
责任链模式使得很容易添加一个自定义拦截器对请求和返回结果进行处理