OkHttp网络请求流程

QuibblerQuibbler 2021-03-16 约 11 分钟 1917 次阅读

OkHttp网络请求流程

经过前面多篇博客的铺垫,终于来了。让我们继续深入OkHttp源码,了解OkHttp网络请求的实现。

val requestBuilder: Request.Builder = Request.Builder()
    ...
    val request: Request = requestBuilder.build()
    val call: Call = okHttpClient.newCall(request)

在OkHttp的基本用法一文中我们了解到,拿到Call实例后,有两种网络请求:异步和同步。

1、异步请求

从Call的enqueue(responseCallback: Callback)方法开始:


从OkHttpClient调用newCall(Request)方法获取Call实例,返回的是RealCall对象:

/** 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接口,enqueue(responseCallback: Callback)方法实现如下:

override fun enqueue(responseCallback: Callback) {
        check(executed.compareAndSet(false, true)) { "Already Executed" }
        callStart()
        client.dispatcher.enqueue(AsyncCall(responseCallback))
    }

通过构造RealCall中的inner类AsyncCall封装当前的RealCall和Callback回调。并将其放入Dispatcher调度器中的异步等待队列readyAsyncCalls。

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()
  }

调用promoteAndExecute()方法推进任务队列的执行。

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()
        ...
        //将接下来执行的AsyncCall放入执行队列runningAsyncCalls中
        runningAsyncCalls.add(asyncCall)
      }
      isRunning = runningCallsCount() > 0
    }
    for (i in 0 until executableCalls.size) {
      val asyncCall = executableCalls[i]
      asyncCall.executeOn(executorService)
    }
    return isRunning
  }

再回到AsyncCall中,调用它的executeOn(executorService: ExecutorService)方法,传入Dispatcher中的执行器ExecutorService。

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!
        }
      }
    }

看到通过Executor执行自身,毫无疑问,AsyncCall继承自Runnable,直接看它的run()方法实现:

override fun run() {
      ...
      try {
        val response = getResponseWithInterceptorChain()
        signalledCallback = true
        responseCallback.onResponse(this@RealCall, response)
      } catch (e: IOException) {
        ...
      } catch (t: Throwable) {
        ...
      } finally {
        //最后,将执行过的AsyncCall从开始加入的runningAsyncCalls中移除
        client.dispatcher.finished(this)
      }
  }

在run()中调用OkHttp网络请求核心方法:getResponseWithInterceptorChain(),经过层层拦截器调用链获取网络请求。这里暂不对该方法展开分析,在OkHttp拦截器Interceptor一文中详细分析。

拿到Response网络请求响应,回调直接创建网络请求时构造的Callback实例

interface Callback {
    fun onFailure(call: Call, e: IOException)
    fun onResponse(call: Call, response: Response)
  }

最后,将执行过的异步任务从异步执行队列runningAsyncCalls中移除。

/** Used by [AsyncCall.run] to signal completion. */
  internal fun finished(call: AsyncCall) {
    call.callsPerHost.decrementAndGet()
    finished(runningAsyncCalls, call)
  }

2、同步请求

同步请求逻辑比异步请求要简单直接一些。


直接执行Call实例的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)
    }
  }

接着调用Dispatcher的execute()方法,是不是用Dispatcher执行呢?不是,只是将RealCall放到runningSyncCalls同步执行队列中,请求完毕最后在finally中移除。

/** Used by [Call.execute] to signal it is in-flight. */
  @Synchronized internal fun executed(call: RealCall) {
    runningSyncCalls.add(call)
  }

紧接着才是getResponseWithInterceptorChain()OkHttp网络请求核心方法。该方法封装网络请求、拦截器、连接池等等,返回Response响应。所以直接执行execute()要放到子线程中。

相关推荐

精选
Airbnb开源项目
开源

Airbnb开源项目

Airbnb Engineering & Data ScienceAirflow Use Apache Airflow (incubating) to author workflows as directed acyclic graphs (DAGs) of tasks12,263Airpal Web UI for PrestoDB2,502Aerosolve A machine learning

1.8k
OkHttp线程池和连接池
开源

OkHttp线程池和连接池

OkHttp线程池和连接池了解了OkHttp的网络请求流程以及拦截器实现原理,再关注OkHttp中两个重要的:OkHttp的线程池和连接池。1、OkHttp线程池在OkHttp网络请求流程一文中,我们分析了OkHttp异步和同步请求流程。请求最后都在Dispatcher中分发调度处理,最后被ExecutorService执行。1.1、DispatcherDispatcher中执行任务的执行器是ex

5.2k
优美的开源动效库:Lottie
开源

优美的开源动效库:Lottie

优美的开源动效库:Lottie1、强大的动效LottieLottie是一个适用于Android,iOS,Web和Windows的库,它可以使用Bodymovin解析以json格式导出的Adobe After Effects动画,并在移动设备和Web上原生渲染它们!GitHub:https://github.com/airbnb/lottie-androidLottie官网:http://airbn

4.3k