Android OkHttp 源码浅析一

演进之路:原生Android框架不好用 ---- HttpUrlConnect 和 Apache HTTPClient

第一版 底层使用HTTPURLConnect

第二版 Square构建 从Android4.4开始

基本使用:

复制代码
 val okhttp = OkHttpClient()
        val request = Request.Builder()
            .url("http://www.baidu.com")
            .build()
        okhttp.newCall(request)
            .enqueue(object : okhttp3.Callback{
                override fun onFailure(call: okhttp3.Call, e: IOException) {
                    Log.e("--->",e.message!!)
                }

                override fun onResponse(call: okhttp3.Call, response: okhttp3.Response) {
                    Log.e("--->",response.body!!.string())
                }

            })

//enqueue Call接口定义的抽象方法
//newCall RealCall创建出 有三个参数 1 okhttpclient  2.quest originnalRequest 3. forWebSocket //Booleaan
//WebSocket 是通过http创建连接
//

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

    callStart()
//dispatcher 用来做线程调度 管理 Executor 线程池
//MaxRequests  = 64 最大64个线程  
//MaxRequestPerHost = 5 最多同一主机线程  5

    client.dispatcher.enqueue(AsyncCall(responseCallback))
  }

  override fun isExecuted(): Boolean = executed.get()

  private fun callStart() {
//跟踪错误分析和记录
    this.callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()")
//监听一系列事件 连接建立 断开连接 报文 head body 发送等
    eventListener.callStart(this)
  }
复制代码
@get:Synchronized var maxRequests = 64 最多连接数量 64
复制代码
@get:Synchronized var maxRequestsPerHost = 5 同一主机 5
复制代码
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()
  }

同步方法,Deque 双向队列

复制代码
AsyncCall 共享变量 记录连接数等
复制代码
if (!call.call.forWebSocket) {

//记录数量
  val existingCall = findExistingCallWithHost(call.host)
  if (existingCall != null) call.reuseCallsPerHostFrom(existingCall)
}
复制代码
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
  }
复制代码
promoteAndExecute 准备执行函数
复制代码
readyAsyncCalls 没有执行过的请求 不会超出限制 64 or 5

executableCalls 添加到calls 然后取出遍历 执行 executeOn

复制代码
val i = readyAsyncCalls.iterator() 遍历被执行的call
复制代码
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)

runningAsyncCalls 正在执行的Call

for (i in 0 until executableCalls.size) {

val asyncCall = executableCalls[i]

遍历准备执行的call 然后调用executeOn

asyncCall.executeOn(executorService)

}

Okhttp enqueue ----> newCall ---> RealCall enqueue ------> 执行 dispatcher . enqueue ----> 添加到readyAsyncCalls ----> promoteAndExecute ---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!
        }
      }
    }

executorService dispatcher 内部类管理的对象 线程调度 参数是runnable

executorService.execute(this) 线程切换到后台线程 Async 实现了Runnable

线程调度

复制代码
 override fun run() {
      threadName("OkHttp ${redactedUrl()}") {
        var signalledCallback = false
        timeout.enter()
        try {
          val response = getResponseWithInterceptorChain()
          signalledCallback = true
          responseCallback.onResponse(this@RealCall, response)
        } catch (e: IOException) {
          if (signalledCallback) {
            // Do not signal the callback twice!
            Platform.get().log("Callback failure for ${toLoggableString()}", Platform.INFO, e)
          } else {
            responseCallback.onFailure(this@RealCall, e)
          }
        } catch (t: Throwable) {
          cancel()
          if (!signalledCallback) {
            val canceledException = IOException("canceled due to $t")
            canceledException.addSuppressed(t)
            responseCallback.onFailure(this@RealCall, canceledException)
          }
          throw t
        } finally {
          client.dispatcher.finished(this)
        }
      }
    }

val response = getResponseWithInterceptorChain() 获取相应

getResponseWithInterceptorChain 请求数据的方法封装

responseCallback 代码里声明传入的Callback

相关推荐
每次的天空8 天前
Android学习总结之OKHttp拦截器和缓存
android·学习·okhttp
东方芷兰9 天前
JavaWeb 课堂笔记 —— 04 Ajax
笔记·ajax·okhttp
隔壁小查10 天前
【后端开发】初识Spring IoC与SpringDI、图书管理系统
java·spring·okhttp
quo-te10 天前
AJAX简介
前端·ajax·okhttp
seabirdssss17 天前
通过动态获取项目的上下文路径来确保请求的 URL 兼容两种启动方式(IDEA 启动和 Tomcat 部署)下都能正确解析
java·okhttp·tomcat·intellij-idea
ps酷教程17 天前
Apache httpclient & okhttp(2)
okhttp·apache
Code额18 天前
认识 Promise
okhttp·promise
ps酷教程20 天前
OkHttp&HttpClient
okhttp·httpclient
东东__net24 天前
27_promise
okhttp
阿湯哥24 天前
SSE SseEmitter.completeWithError(e) 触发的处理逻辑
okhttp