一文摸懂OkHttp,Android性能优化推荐书

// 对每一个进入了运行队列中的请求进行正式运行

for (i in 0 until executableCalls.size) {

val asyncCall = executableCalls[i]

asyncCall.executeOn(executorService)

}

return isRunning

}

想来对整个的处理过程已经有一个比较详细的讲解了,但是我们还是没有看到数据的返回操作,甚至说具体的运行,不过我们能够注意到一个中途意外冒出的变量executorService,这个变量是从哪里来的呢?

溯源我们能够发现,他在Dispatcher中就已经有过了初始化操作。

@get:JvmName(“executorService”) val executorService: ExecutorService

get() {

if (executorServiceOrNull == null) {

executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,

SynchronousQueue(), threadFactory(“$okHttpName Dispatcher”, false))

}

return executorServiceOrNull!!

}

一看到要说ThreadPoolExecutor,哦哦哦哦!线程池,但是和什么线程池长得特别像呢?进入已经定义好的Executors类中查找,能够查找到如下的代码段:

public static ExecutorService newCachedThreadPool() {

return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

60L, TimeUnit.SECONDS,

new SynchronousQueue());

}

是不是有点像呢?那好,我们就认定了它是我们的CachedThreadPool线程池。

ok!fine!用的线程池来进行异步操作,那肯定就是说明里面有一个线程了,那这个线程是啥,我们是否心里有点数呢?如果没有,也没啥关系,下面我们将继续引出。

fun executeOn(executorService: ExecutorService) {

client.dispatcher.assertThreadDoesntHoldLock()

var success = false

try {

executorService.execute(this) // (1)

success = true

} catch (e: RejectedExecutionException) {

val ioException = InterruptedIOException(“executor rejected”)

ioException.initCause(e)

noMoreExchanges(ioException)

responseCallback.onFailure(this@RealCall, ioException) // (2)

} finally {

if (!success) {

client.dispatcher.finished(this) // (3)

}

}

}

那接下来就又不是什么大问题了,主要就看到我们的注释1、2、3。

  1. executorService.execute(this):对于线程池而言运行的显然是线程,而this几就是我们的AsyncCall,通过对AsyncCall的观察我们也是能够得知它是继承了Runnable的,所以异步进行的操作来源我们也已经清楚了。

  2. responseCallback.onFailure(),也就是通过我们传入的Callback接收数据的错误反馈。

  3. client.dispatcher.finished(this):为什么需要这个呢?其实他原本有这样的一段英文注释,This call is no longer running!,也就是说明这个函数是为了通知Dispatcher我们的AsyncCall已经完成了运行。

又开始有问题了吧,看着就着急。咋就没看到responseCallback()onResponse方法的使用呢???

那我们做一个猜测吧,其实我看了一下基本也是正解了。我们的不是Runnable嘛,而数据是放在线程池中run()来运行的,那么onResponse()方法的出现应该是在run()的这个函数中了。接下来我们继续收看代码

override fun run() {

threadName(“OkHttp ${redactedUrl()}”) {

var signalledCallback = false

timeout.enter()

try {

val response = getResponseWithInterceptorChain() // (1)

signalledCallback = true

responseCallback.onResponse(this@RealCall, response) //(2)

} catch (e: IOException) {

// 。。。。。

responseCallback.onFailure(this@RealCall, e)

} catch (t: Throwable) {

// 。。。。。

responseCallback.onFailure(this@RealCall, e)

} finally {

client.dispatcher.finished(this)

}

}

}

在这里的注释(2)中,我们很幸运的看到了onResponse()的方法调用了。好那接下来就是下一个问题了,Response是从哪里来的????

Response的诞生


上面不是写着嘛??getResponseWithInterceptorChain()这个函数里来的呗。哇哦!!没错了,那它是怎么来的? 🤔🤔🤔

又要看代码了,好烦好烦。。。

internal fun getResponseWithInterceptorChain(): Response {

// Build a full stack of interceptors.

val interceptors = mutableListOf()

// 对应着我们刚开始自定义的拦截器

interceptors += client.interceptors

interceptors += RetryAndFollowUpInterceptor(client)

interceptors += BridgeInterceptor(client.cookieJar)

interceptors += CacheInterceptor(client.cache)

interceptors += ConnectInterceptor

// 我们之前上面也出现过forWebSocket这个flag

// 其实它是okhttp为了长连接而准备的

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

)

val response = chain.proceed(originalRequest)

return response

}

为了尽量让代码简洁明了,我截取了一些关键代码,以供参考。

其实他就是通过一堆的拦截器来获取数据的,但是显然这里不是终点站,因为我们看到的return中就还是一个函数,说明答案还在这个函数中。通过观察我们很容易得知,这个的操作的具体类是一个叫做RealInterceptorChain的类。

override fun proceed(request: Request): Response {

// 不断调用下一个拦截器对相应的数据进行返回

val next = copy(index = index + 1, request = request)

val interceptor = interceptors[index]

val response = interceptor.intercept(next)

return response

}

如图所示,哪个拦截器能拦截成功,就会返回我们需要的数据Response,当然这个数据你需要注意,并不一定是成功的数据,一般来说数据成功的获取都需要走到我们的响应拦截器之后才能真正的成功。

CacheInterceptor缓存拦截器的源码解读


这里我们需要重点讲解一下CacheInterceptor这个类,我们截取他的intercept()方法,因为里面涉及了我们面试时可能会频繁使用的响应码

override fun intercept(chain: Interceptor.Chain): Response {

// 依据我们传入的request得到cache中缓存的response

val cacheCandidate = cache?.get(chain.request())

val now = System.currentTimeMillis()

// 获取当前的这个请求是网络请求、数据缓存的状况

val strategy = CacheStrategy.Factory(now, chain.request(), cacheCandidate).compute()

val networkRequest = strategy.networkRequest

val cacheResponse = strategy.cacheResponse

cache?.trackResponse(strategy)

if (cacheCandidate != null && cacheResponse == null) {

// The cache candidate wasn’t applicable. Close it.

cacheCandidate.body?.closeQuietly()

}

// 本地查询到的网络请求和缓存数据皆为空的情况下

// 爆HTTP_GATEWAY_TIMEOUT,网关超时的错误

if (networkRequest == null && cacheResponse == null) {

return Response.Builder()

.request(chain.request())

.protocol(Protocol.HTTP_1_1)

.code(HTTP_GATEWAY_TIMEOUT)

.message(“Unsatisfiable Request (only-if-cached)”)

.body(EMPTY_RESPONSE)

.sentRequestAtMillis(-1L)

.receivedResponseAtMillis(System.currentTimeMillis())

.build()

}

// 没有网络情况下,直接使用我们本地的数据缓存

if (networkRequest == null) {

return cacheResponse!!.newBuilder()

.cacheResponse(stripBody(cacheResponse))

.build()

}

// 调动责任链中下一轮的拦截器,来获取数据

var networkResponse: Response? = null

try {

networkResponse = chain.proceed(networkRequest)

} finally {

// If we’re crashing on I/O or otherwise, don’t leak the cache body.

if (networkResponse == null && cacheCandidate != null) {

cacheCandidate.body?.closeQuietly()

}

}

// 观察我们本地是否存在数据缓存

if (cacheResponse != null) {

// HTTP_NOT_MODIFIED:304,说明我们本地的缓存是最新的

// 没有必要将数据从服务器拉取进行更新了

if (networkResponse?.code == HTTP_NOT_MODIFIED) {

val response = cacheResponse.newBuilder()

.headers(combine(cacheResponse.headers, networkResponse.headers))

.sentRequestAtMillis(networkResponse.sentRequestAtMillis)

.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis)

.cacheResponse(stripBody(cacheResponse))

.networkResponse(stripBody(networkResponse))

.build()

networkResponse.body!!.close()

// Update the cache after combining headers but before stripping the

// Content-Encoding header (as performed by initContentStream()).

cache!!.trackConditionalCacheHit()

cache.update(cacheResponse, response)

return response

} else {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

现在。**

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-i83VO42j-1710945956923)]
[外链图片转存中…(img-9m7m8y71-1710945956924)]
[外链图片转存中…(img-DDpR0brY-1710945956924)]
[外链图片转存中…(img-Z6Fhn1v8-1710945956925)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-tpbTnwxv-1710945956925)]

  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值