本文基于OkHttp4.9.1
关于OkHttp这个东西大家都很熟悉了吧,那么对于它的请求流程你了解吗,你还在停留在知其然而不知其所以然的阶段码。来看一下我对它的理解吧
使用方式
fun requestTest() {
val url = "https://www.wanandroid.com/banner/json"
val client = OkHttpClient();
val request = Request.Builder()
.url(url)
.build()
//异步请求
client.newCall(request).enqueue(object : Callback {//1
override fun onFailure(call: Call, e: IOException) {
}
override fun onResponse(call: Call, response: Response) {
}
})
//同步请求
client.newCall(request).execute()//2
}
以上代码是OkHttp的基础使用方式,也是我们最方便切入框架结构的代码块。
异步请求
源码阅读选择哪个作为入口呢,当然是最接近功能实现的enqueue()方法了了。进入enqueue()方法发现它是一个抽象方法,它所在的类也是一个接口类。那么只能寻求它的上级实现了,进入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对象。RealCall有三个参数 val client: OkHttpClient、 val originalRequest: Request、 val forWebSocket: Boolean。client负责OkHttp的通用配置,originalRequest负责OkHttp的请求发起,forWebSocket用来判断是否需要以WebSocket形式建立请求连接。既然找到了newCall()创建的对象,那么就可以看一下enqueue()方法的实现了
override fun enqueue(responseCallback: Callback) {
check(executed.compareAndSet(false, true)) { "Already Executed" }
callStart()//3
client.dispatcher.enqueue(AsyncCall(responseCallback))//4
}
private fun callStart() {
//跟踪程序,在程序出错时进行错误分析
this.callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()")
//监听反馈
eventListener.callStart(this)
}
在RealCall##enqueue()的注释3的主要就是负责程序的错误分析以及流程监听反馈,注释4是enqueue()方法的执行关键,它调用了dispatcher的enqueue()方法并且向其中传入了一个AsyncCall对象。dispatcher是一个Dispatcher对象,Dispatcher类在OkHttp中负责线程的调度处理,功能由ExecutorService实现,有兴趣的同学可以单独去看一下Dispatcher源码。现在看一下Dispatcher##enqueue()
internal fun enqueue(call: AsyncCall) {
synchronized(this) {
readyAsyncCalls.add(call)
// Mutate the AsyncCall so that it shares the AtomicInteger of an existing running call to
// the same host.
if (!call.call.forWebSocket) {
val existingCall = findExistingCallWithHost(call.host)
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
}
promoteAndExecute()
}
private fun promoteAndExecute(): Boolean {
this.assertThreadDoesntHoldLock()
val executableCalls = mutableListOf()
val isRunning: Boolean
synchronized(this) {
val i = readyAsyncCalls.iterator()
while (i.hasNext()) {
val asyncCall = i.next()
if (runningAsyncCalls.size >= this.maxRequests) break // 5
if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue //6
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
}
readyAsyncCalls是一个双向队列,负责保存即将运行的AsyncCall对象。promoteAndExecute()中会对readyAsyncCalls进行遍历,将满足条件的AsyncCall对象取出放入executableCalls集合中,executableCalls保存的就是正在执行的AsyncCall对象。条件筛选是注释5及注释6,目的是防止程序过载。筛选完成后会对重新赋值的executableCalls进行遍历,取出其中的AsyncCall对象执行executeOn()方法
fun executeOn(executorService: ExecutorService) {
client.dispatcher.assertThreadDoesntHoldLock()
var success = false
try {
executorService.execute(this)
success = true
} catch (e: RejectedExecutionException) {
val ioException = InterruptedIOException("executor rejected")
ioException.initCause(e)
noMoreExchanges(ioException)
responseCallback.onFailure(this@RealCall, ioException)
} finally {
if (!success) {
client.dispatcher.finished(this) // This call is no longer running!
}
}
}
AsyncCall##executeOn()核心只有一行executorService.execute(this),通过线程池来执行一个任务。AsyncCall自己实现了Runnable接口,所以只需要看一下AsyncCall##run()方法即可
override fun run() {
threadName("OkHttp ${redactedUrl()}") {
var signalledCallback = false
timeout.enter()
try {
val response = getResponseWithInterceptorChain()
signalledCallback = true
responseCallback.onResponse(this@RealCall, response)
}
......
......
}
}
在AsyncCall##run()其实也只有一行关键代码 val response = getResponseWithInterceptorChain(),拿到请求返回,然后通过responseCallback将结果回传responseCallback就是我们注释1中传入的Callback。如此一个异步请求流程就完成了
同步请求
前文分析异步方法enqueue()实现在RealCall类中,那么同步方法execute()也实现在
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)
}
}
直接就是返回了getResponseWithInterceptorChain()的返回结果
至此OkHttp的同步异步调用流程便分析完了。关于getResponseWithInterceptorChain()方法我会在另一篇文章中解析