导言
在 Android
开发的国际中,有一些组件,不管运用层技能再怎样迭代,作为根底支撑,它们仍然在那里。
比方当咱们提到网络库时,总会下意识想到一个姓名,即 OkHttp
。
尽管关于大多数开发者而言,通常状况下运用的是往往它的封装版本 Retrofit
,不过其底层仍然离不开 Okhttp
作为根底支撑。而不管是自研网络库的二次封装,仍是个人运用,OkHttp
也往往都是不贰之选。
故本篇将以最新视角开端,用力一瞥 OkHttp
的规划魅力。
本文对应的 OkHttp
版本: 4.10.0
本篇定位 中高难度,将从布景到运用办法,再到规划思维与源码解析,尽可能全面、易懂。
布景
每一个技能都有其变迁的前史布景与特性,本末节,咱们将聊一聊 Android网络库 的迭代史,作为开篇引语,润润眼。
关于 Android网络库 的迭代前史,如下图所示:
详细进展如下:
-
HttpClient
Android1.0
时推出。但存在诸多问题,比方内存泄漏,频频的GC等。5.0后,已被弃用; -
HttpURLConnection
Android2.2
时推出,比HttpClient
更快更安稳,Android4.4 之后底层现已被Okhttp
代替; -
volley
Google 2013年开源,基于
HttpURLConnection
的封装,具有良好的扩展性和适用性,不过关于杂乱恳求或许很多网络恳求时,功能较差。现在仍然有不少项目运用(通常是老代码的保护); -
okhttp
Square 2013年开源,基于 原生Http 的底层规划,具有 快速 、 安稳 、节约资源 等特色。是现在诸多热门网络恳求库的底层完结,比方
Retrofit
、RxHttp
等; -
Retrofit
Square 2013年开源,基于
OkHttp
的封装,现在 干流 的网络恳求库。经过注解办法装备网络恳求、REST风格 api、解耦完全、经常会调配 Rx等 完结 结构联动;
-
…
上述的整个进程,也正是伴随了 Android
开发的各个时期,假如将上述分为 5个阶段 的话,那么则为:
HttpClient
->HttpURLConnection
->volley
->okhttp
->Retrofit
*
经过 Android网络库 的迭代前史,咱们不难发现,技能变迁越来越趋于安稳,而 OkHttp
也现已成为了根底组件中不行所缺的一员。
规划思维
当聊到OkHttp的规划思维,咱们想知道什么?
从运用层去看,娴熟的开发者会直接喊出阻拦器,巴拉巴拉…
而作为初学者,可能更期望的事广度与解惑,
OkHttp
究竟牛在了什么地方,或许说常说的 阻拦器究竟是什么 ?
在官方的描述中,OkHttp
是一个高效的 Http恳求结构 ,旨在 简化 客户端网络恳求,进步 恳求功率。
详细规划思维与特性如下:
- 衔接复用 :防止在每个恳求之间从头树立衔接。
- 衔接池 降低了恳求延迟 (HTTP/2不行用状况下);
- 主动重试 :在恳求失利时主动重试恳求,然后进步恳求可靠性。
- 主动处理缓存 :会依照预定的缓存战略处理缓存,以便最大化网络功率。
- 支撑HTTP/2, 而且允许对同一个主机的一切恳求同享一个套接字(HTTP/2);
- 简化Api:Api规划简略明了,易于运用,能够轻松建议恳求获取呼应,并处理反常。
- 支撑gzip紧缩 :OkHttp支撑gzip紧缩,以便经过削减网络数据的巨细来进步网络功率。
特别的,假如咱们的服务器或许域名有 多个IP地址 ,OkHttp
将在 第一次 衔接失利时测验代替原有的地址(关于 IPv4+IPv6 和保管在冗余数据中心的服务是必需的)。而且支撑现代 TLS 功能(TLS 1.3、ALPN、证书固定)。它能够装备为回退以完结广泛的衔接。
总的来说,其规划思维是经过 简化恳求进程 、进步恳求功率、进步恳求可靠性,然后供给 更快的呼应速度 。
运用层的整个恳求结构图如下:
运用办法
在开端探究规划原理与思维之前,咱们仍是要先看看最根底的运用办法,以便为后续做一些铺垫。
// build.gradle
implementation "com.squareup.okhttp3:okhttp:4.10.0"
// Android Manifest
<uses-permission android:name="android.permission.INTERNET" />
建议一个get恳求
阻拦器的运用
总结起来便是下面几步:
- 创立
OkHttpClient
目标;- 构建
Request
;- 调用
OkHttpClient
履行request
恳求 ;- 同步堵塞 或许 异步回调 办法接纳成果;
更多运用办法,能够在查找其他同学的教程,这儿仅仅仅仅作为后续解析原理时的必要根底支撑。
源码剖析
根底装备
OkHttpClient
val client = OkHttpClient.Builder().xxx.build()
由上述调用办法,咱们便能够猜出,这儿运用了 构建者形式 去装备默许的参数,所以直接去看 OkHttpClient.Builder
支撑的参数即可,详细如下:
详细的属性意思在代码中也都有注释,这儿咱们就不在多提了。
需求留意的是,在运用进程中,关于 OkHttpClient
咱们仍是应该缓存下来或许运用单例形式以便后续复用,由于其相对而言仍是比较重。
Request
指客户端发送到服务器的 HTTP恳求。
在 OkHttp
中,能够运用 Request
目标来构建恳求,然后运用 OkHttpClient
目标来发送恳求。
通常状况下,一个恳求包括了 恳求头、恳求办法、恳求途径、恳求参数、url地址 等信息。首要是用来恳求服务器回来某些资源,如网页、图片、数据等。
详细源码如下所示:
Request.Builder().url("https://www.baidu.com").build()
open class Builder {
// url地址
internal var url: HttpUrl? = null
// 恳求办法
internal var method: String
// 恳求头
internal var headers: Headers.Builder
// 恳求体
internal var body: RequestBody? = null
// 恳求tag
internal var tags: MutableMap<Class<*>, Any>
}
建议恳求
execute()
用于履行 同步恳求 时调用,详细源码如下:
client.newCall(request).execute()
接下来咱们再去看看 client.newCall()
, 即恳求建议时的逻辑。
当咱们运用 OkHttpClient.newCall()
办法时,实践是创立了一个新的 RealCall
目标,用于 运用层与网络层之间的桥梁,用于处理衔接、恳求、呼应以及流 ,其默许构造函数中需求传递 okhttpClient
目标以及 request
。
接着,运用了 RealCall
目标调用了其 execute()
办法开端建议恳求,该办法内部会将当时的 call
参加咱们 Dispatcher
分发器内部的 runningSyncCalls
行列中取,等候被履行。接着调用 getResponseWithInterceptorChain()
,运用阻拦器获取本次恳求呼应的内容,这也即咱们接下来要重视的进程。
enqueue()
履行 异步恳求 时调用,详细源码如下:
client.newCall(request).enqueue(CallBack)
当咱们调用 RealCall.enqueue()
履行异步恳求时,会先将本次恳求参加 Dispather.readyAsyncCalls
行列中等候履行,假如当时恳求是 webSocket
恳求,则查找与当时恳求是同一个 host
的恳求,假如存在共同的恳求,则复用先前的恳求。
接下来调用 promoteAndExecute()
将一切符合条件能够恳求的 Call
从等候行列中增加到 可恳求行列 中,再遍历该恳求行列,将其增加到 线程池 中去履行。
继续沿着上面的源码,咱们去看 asyncCall.executeOn(executorService)
,如下所示:
上述逻辑也很简略,当咱们将任务增加到线程池后,当任务被履行时,即触发 run()
办法的调用。该办法中会去调用 getResponseWithInterceptorChain()
然后运用阻拦器链获取服务器呼应,然后完结本次恳求。恳求成功后则调用咱们开端时的 callback目标 的 onResponse()
办法,反常(即失利时)则调用 onFailure()
办法。
阻拦器链
在上面咱们知道,他们终究都走到了 RealCall.getResponseWithInterceptorChain()
办法,即运用 阻拦器链 获取本次恳求的呼应内容。不过关于初看OkHttp源码的同学,这一步运用会有点迷惑,阻拦器链 是什么东东?
在解说 阻拦器链 之前,咱们不妨先看一下 RealCall.getResponseWithInterceptorChain()
办法对应的源码完结,然后再去解说为什么,或许更简略了解。
详细源码如下:
上述的逻辑十分简略,内部会先创立一个部分阻拦器调集,然后将咱们自己设置的一般阻拦器增加到该调集中,然后增加中心的5大阻拦器,接着再将咱们自定义的网络阻拦器也增加到该调集中,终究才增加了真实用于履行网络恳求的阻拦器。接着创立了一个阻拦器职责链 RealInterceptorChain
,并调用其 proceed()
办法开端履行本次恳求。
职责链形式
在上面咱们说到了,要解说 OkHttp
的阻拦器链,咱们有必要简略聊一下什么是职责链形式?
职责链形式(Chain of Responsibility)是一种处理恳求的形式,它让多个处理器都有机会处理该恳求,直到其间某个处理成功停止。职责链形式把多个处理器串成链,然后让恳求在链上传递。
摘自 职责链形式 @廖雪峰
以 Android
中常见的事情分发为例:当咱们的手指点击屏幕开端,用户的触摸事情从 Activity
开端分发,接着从 windows
开端分发到详细的 contentView(ViewGroup)
上,开端调用其 dispatchTouEvent()
办法进行事情分发。在这个办法内,假如当时 ViewGroup
不进行阻拦,则默许会继续向下分发,寻觅当时 ViewGroup
下对应的触摸方位 View
,假如该 View
是一个 ViewGroup
,则重复上述进程。假如事情被某个 view
阻拦,则触发其 onTouchEvent()
办法,接着交由该view去消费该事情。而假如事情传递到最上层 view
仍是没人消费,则该事情开端依照原路回来,先交给当时 view
自己的 onTouchEvent()
,由于自己不消费,则调用其 父ViewGroup
的 onTouchEvent()
,如此层层传递,终究又交给了 Act
自行处理。上述这个流程,便是 职责链形式 的一种表现。
如下图所示:
上图来自 Android事情分发机制三:事情分发作业流程 @一只修仙的猿
看完什么是职责链形式,让咱们将思路转回到 OkHttp
上面,咱们再去看一下 RealInterceptorChain
源码。
上述逻辑如下:
-
当
getResponseWithInterceptorChain()
办法内部终究调用RealInterceptorChain.proceed()
时,内部传入了一个默许的index ,这个 index 就代表了当时要调用的 阻拦器item ,并在办法内部每次创立一个新的RealInterceptorChain
链,index+1,再调用当时阻拦器intercept()
办法时,然后将下一个链传入; -
最开端调用的是用户自定义的 一般阻拦器,假如上述咱们增加了一个
CustomLogInterceptor
的阻拦器,当获取response
时,咱们需求调用Interceptor.Chain.proceed()
,而此刻的chain
正是下一个阻拦器对应的RealInterceptorChain
; -
上述流程里,index从0开端,以此类推,一直到链条末尾,即 阻拦器调集长度-1处;
-
当遇到终究一个阻拦器
CallServerInterceptor
时,此刻由于现已是终究一个阻拦器,链条必定要完毕了,所以其内部必定也不会调用proceed()
办法。相应的,为什么咱们在前面说 它 是真实履行与服务器树立实践通讯的阻拦器?
由于这个里会获取与服务器通讯的
response
,即最初呼应成果,然后将其回来上一个阻拦器,即咱们的网络阻拦器,再接着又向上回来,终究回来到咱们的一般阻拦器处,然后完结整个链路的路由。
参照上面的流程,即大致思路图如下:
阻拦器
RetryAndFollowUpInterceptor
见名知意,用于 恳求失利 的 重试 作业以及 重定向 的后续恳求作业,一起还会对 衔接 做一些初始化作业。
上述的逻辑,咱们分为四段进行剖析:
- 恳求时假如遇到反常,则依据状况去测验康复,假如不能康复,则抛出反常,越过本次恳求;假如恳求成功,则在
finally
里开释资源; - 假如恳求是重试之后的恳求,那么将重试前恳求的呼应体设置为null,并增加到当时呼应体的
priorResponse
字段中; - 依据当时的responseCode判别是否需求重试,若不需求,则回来
response
;若需求,则回来request
,并在后续查看当时重试次数是否达到阈值; - 重复上述进程,直到进程三成功。
在第一步时,获取 response
时,需求调用 realChain.proceed(request)
,假如你还记得上述的职责链,所以这儿触发了下面的阻拦器履行,即 BridgeInterceptor
。
BridgeInterceptor
用于 客户端和服务器 之间的交流 桥梁 ,担任将用户构建的恳求转换为服务器需求的恳求。比方增加 content-type
、cookie
等,再将服务器回来的 response
做一些处理,转换为客户端所需求的 response
,比方移除 Content-Encoding
,详细见下面源码所示:
上述逻辑如下:
- 首要调用
chain.request()
获取原始恳求数据,然后开端从头构建恳求头,增加header
以及cookie
等信息; - 将第一步构建好的新的
request
传入chain.proceed()
,然后触发下一个阻拦器的履行,并得到 服务器回来的response
。然后保存response
带着的cookie
,并移除header
中的Content-Encoding
和Content-Length
,并同步修正body
。
CacheInterceptor
见名知意,其用于网络缓存,开发者能够经过 OkHttpClient.cache()
办法来装备缓存,在底层的完结处,缓存阻拦器经过 CacheStrategy
来判别是运用网络仍是缓存来构建 response
。详细的 cache
战略采用的是 DiskLruCache
。
Cache的战略如下图所示:
详细源码如下所示:
详细的逻辑如上图所示,详细能够参照上述的 Cache
流程图,这儿咱们再说一下 CacheStrategy
这个类,即决议何时运用 网络恳求、呼应缓存。
CacheStrategy
ConnectInterceptor
完结与服务器真实的衔接。
上述流程如下:
- 初始化 一个
exchange
目标; - 依据
exchange
目标来仿制创立一个新的衔接职责链; - 履行该衔接职责链。
那 Exchange 是什么呢?
在官方的解说里,其用于 传递单个
HTTP
恳求和呼应对,在ExchangeCode
的根底上背负了一些办理及事情分发的作用。详细而言,
Exchange
与Request
相对应,新建一个恳求时就会创立一个Exchange
,该Exchange
担任将这个恳求发送出去并读取到呼应数据,而详细的发送与接纳数据运用的则是ExchangeCodec
。
相应的,ExchangeCode 又是什么呢?
ExchangeCodec
担任对request
编码及解码Response
,即写入恳求及读取呼应,咱们的恳求及呼应数据都是经过它来读写。通俗一点便是,ExchangeCodec 是恳求处理器,它内部封装了
OkHttp
中履行网络恳求的细节完结,其经过接受一个Request
目标,并在内部进行处理,终究生成一个符合HTTP
协议标准的网络恳求,然后接受服务器回来的HTTP呼应,并生成一个Response
目标,然后完结网络恳求的整个进程。
额外的,咱们还需求再提一个类,ExchangeFinder 。
用于寻觅可用的
Exchange
,然后发送下一个恳求并接受下一个呼应。
虽然上述流程看起来似乎很简略,但咱们仍是要剖析下详细的流程,源码如下所示:
RealCall.initExchange()
初始化 Exchage
的进程。
从 ExchangeFinder
找到一个新的或许现已存在的 ExchangeCodec
,然后初始化 Exchange
,以此来承载接下来的HTTP恳求和呼应对。
ExchangeFinder.find()
查找 ExchangeCodec
(恳求呼应编码器) 的进程。
接下来咱们看看查找 RealConnection
的详细进程:
上述的整个流程如下:
上述会先经过 ExchangeFinder
去 RealConnecionPool
中测验寻觅现已存在的衔接,未找到则会从头创立一个 RealConnection
(衔接) 目标,并将其增加到衔接池里,开端衔接。然后依据找到或许新创立 RealConnection
目标,并依据当时恳求协议创立不同的 ExchangeCodec
目标并回来,终究初始化一个 Exchange
交换器并回来,然后完结了 Exchange
的初始化进程。
在详细找寻 RealConnection
的进程中,一共测验了5次,详细如下:
- 测验重连
call
中的connection
,此刻不需求从头获取衔接; - 测验从衔接池中获取一个衔接,不带路由与多路复用;
- 再次测验从衔接池中获取一个衔接,带路由,不带多路复用;
- 手动创立一个新衔接;
- 再次测验从衔接池中获取一个衔接,带路由与多路复用;
当 Exchange
初始化完结后,再仿制该目标创立一个新的 Exchange
,并履行下一个职责链,然后完结衔接的树立。
networkInterceptors
网络阻拦器,即 client.networkInterceptors 中自定义阻拦器,与一般的阻拦器 client.interceptors
不同的是:
由于网络阻拦器处于倒数第二层,在 RetryAndFollowUpInterceptor
失利或许 CacheInterceptor
回来缓存的状况下,网络阻拦器无法被履行。而一般阻拦器由于第一步就被就履行到,所以不受这个约束。
CallServerInterceptor
链中的终究一个阻拦器,也即与服务器进行通讯的阻拦器,利用 HttpCodec
进行数据恳求、呼应数据的读写。
详细源码如下:
先写入要发送的恳求头,然后依据条件判别是否写入要发送的恳求体。当恳求完毕后,解析服务器回来的呼应头,构建一个新的 response
并回来;假如 response.code
为 100,则从头读取呼应体并构建新的 response
。由于这是最底层的阻拦器,所以这儿必定不会再调用 proceed()
再往下履行。
小结
至此,关于 OkHttp
的剖析,到这儿就完毕了。为了便于了解,咱们再串一遍整个思路:
在 OkHttp
中,RealCall
是 Call
的完结类,其担任 履行网络恳求 。其间,恳求 request
由 Dispatcher
进行调度,其间 异步调用 时,会将恳求放到到线程池中去履行; 而同步的恳求则仅仅会增加到 Dispatcher
中去办理,并不会有线程池参与协调履行。
在详细的恳求进程中,网络恳求依次会经过下列阻拦器组成的职责链,终究发送到服务器。
- 一般阻拦器,
client.interceptors()
; - 重试、重定向阻拦器
RetryAndFollowUpInterceptor
; - 用于客户端与服务器桥梁,将用户恳求转换为服务器恳求,将服务器呼应转换为用户呼应的的
BridgeInterceptor
; - 决议是否需求恳求服务器并写入缓存再回来仍是直接回来服务器呼应缓存的
CacheInterceptor
; - 与服务器树立衔接的
ConnectInterceptor
; - 网络阻拦器,
client.networkInterceptors()
; - 履行网络恳求的
CallServerInterceptor
;
而相应的服务器呼应体则会从 CallServerInterceptor
开端依次往前开端回来,终究由客户端进行处理。
需求留意的是,当咱们
RetryAndFollowUpInterceptor
反常或许CacheInterceptor
阻拦器直接回来了有用缓存,后续的阻拦器将不会履行。
常见问题
OkHttp怎么判别缓存有用性?
这儿其实首要说的是 CacheInterceptor
阻拦器里的逻辑,详细如下:
OkHttp
运用 HTTP协议 中的 缓存操控机制 来判别缓存是否有用。假如恳求头中包括 "Cache-Control"
和 "If-None-Match"
/ "If-Modified-Since"
字段,OkHttp
将依据这些字段的值来决议是否运用缓存或从网络恳求呼应。
Cache-Control
指 包括缓存操控的指令,例如 “no-cache” 和 “max-age” ;
If-None-Match
指 客户端缓存的呼应的ETag值,假如服务器回来相同的 ETag 值,则阐明呼应未修正,缓存有用;
If-Modified-Since
指 客户端缓存的呼应的终究修正时刻,假如服务器确认呼应在此刻间后未更改,则回来304 Not Modified状况码,表示缓存有用。
相应的,OkHttp
也支撑自定义缓存有用性操控,开发者能够创立一个 CacheControl
目标,并将其作为恳求头增加到 Request
中,如下所示:
// 禁止OkHttp运用缓存
val cacheControl = CacheControl.Builder()
.noCache()
.build()
val request = Request.Builder()
.cacheControl(cacheControl)
.url("https://www.baidu.com")
.build()
OkHttp怎么复用TCP衔接?
这个其实首要说的是 ConnectInterceptor
阻拦器中初始化 Exchange
时内部做的事,详细如下:
OkHttp
运用衔接池 RealConnectionPool
办理一切衔接,衔接池将一切活动的衔接存储在池中,并保护了一个空闲的衔接列表(TaskQueue
),当需求新的衔接时,优先测验从这个池中找,假如没找到,则 从头创立 一个 RealConnection
衔接目标,并将其增加到衔接池中。在详细的寻觅衔接的进程中,一共进行了下面5次测验:
- 测验重连
RealCall
中的connection
,此刻不需求从头获取衔接; - 测验从衔接池中获取一个衔接,不带路由与多路复用;
- 再次测验从衔接池中获取一个衔接,带路由,不带多路复用;
- 手动创立一个新衔接;
- 再次测验从衔接池中获取一个衔接,带路由与多路复用;
当然 OkHttp
也支撑自定义衔接池,详细如下:
上述代码中,创立了一个新的衔接池,并设置其保存最多 maxIdleConnections
个空闲衔接,而且衔接的存活期为 keepAliveDuration
分钟。
OKHttp复用TCP衔接的好处是什么?
OkHttp
是由衔接池办理一切衔接,经过衔接池,然后能够约束衔接的 最大数量,而且关于空闲的衔接有相应的 存活期限 ,以便在长时刻不运用后封闭衔接。当恳求完毕时,而且将保存该衔接,便于后续 复用 。然后完结了在多个恳求之间同享衔接,防止屡次树立和封闭TCP衔接的开支,进步恳求功率。
OkHttp中的恳求和呼应 与 网络恳求和呼应,这两者有什么不同?
OkHttp
中的的恳求和呼应指的是客户端创立的恳求目标 Request
和 服务端回来的呼应目标 Response
,这两个目标用于定义恳求和呼应的信息。网络恳求和呼应指的是客户端向服务端发送恳求,服务端回来相应的进程。
总的来说便是,恳求和呼应是运用程序内部自己的事,网络恳求和呼应则是产生在网络上的恳求和呼应进程。
OkHttp 运用阻拦器和网络阻拦器的区别?
- 从调用办法上而言,运用阻拦器指的是
OkhttpClient.intercetors
,网络阻拦器指的是OkHttpClient.netIntercetors
。 - 从整个职责链的调用来看,运用阻拦器一定会被履行一次,而网络阻拦器不一定会履行或许履行屡次状况,比方当咱们
RetryAndFollowUpInterceptor
反常或许CacheInterceptor
阻拦器直接回来了有用缓存,后续的阻拦器将不会履行,相应的网络阻拦器也天然不会履行到;当咱们产生 错误重试 或许 网络重定向 时,网络阻拦器此刻可能就会履行屡次。 - 其次,除了
CallServerInterceptor
与CacheIntercerceptor
缓存有用之外,每个阻拦器都应该至少调用一次realChain.proceed()
办法。但运用阻拦器能够调用屡次processed()
办法,由于其在恳求流程中是能够递归调用;而网络阻拦器只能调用一次processed()
办法,否则将导致恳求重复提交,影响功能,别的,网络阻拦器没有对恳求做修正的可能性,因而不需求再次调用processed()
办法。 - 从 运用办法的 实质而言,运用阻拦器能够 阻拦和修正恳求和呼应 ,但 不能修正网络恳求和呼应 。比方运用运用阻拦器增加恳求参数、缓存恳求成果;网络阻拦器能够阻拦和修正网络恳求和呼应。例如运用网络阻拦器增加恳求头、修正恳求内容、查看呼应码等。
- 在相应的履行次序上,网络阻拦器是
先进先出(FIFO)
,运用阻拦器是先进后出(FILO)
的办法履行。
结语
本篇中,咱们从网络库的迭代前史,一直到 OkHttp
的运用办法、规划思维、源码探究,终究又聊了聊常见的一些问题,然后较体系的了解了 OkHttp
的方方面面,也解说了 OkHttp运用层
的相关问题,当然这些问题我信任也仅仅仅仅冰山一角。 更多面试相关,或许实践问题,仍需求咱们自己再进行完善,然后形成全面的透析力。
这篇文章断断续续写了将近两周,其间必定有不少部分存在缺点或许逻辑漏洞,假如您发现了,也能够告诉我。
经过这篇文章,于我个人而言,也是完结了关于 OkHttp运用层
一次较体系的了解,然后也完善了常识拼图中重要的一块,等待作为读者的你也能有如此或许更深的体会。
更多
这是 解码系列 – OkHttp 篇,假如你觉得这个系列写的还不错,不妨点个重视催更一波,当然也能够看看其他篇:
- 由浅入深,详解 Lifecycle 的那些事
- 由浅入深,详解 LiveData 的那些事
- 由浅入深,详解 ViewModel 的那些事
- 由浅入深,详解 LeakCanary 的那些事
参看
- 深入了解OkHttp源码及规划思维
- OkHttp源码走心解析(很细 很长)
- 拆轮子系列:拆 OkHttp
- OkHttp 源码剖析
关于我
我是 Petterp ,一个 Android工程师 ,假如本文对你有所协助,欢迎 点赞、评论、收藏,你的支撑是我继续创作的最大鼓励!