浅析 OkHttp 源码 - Callback 的调用流程

前言
上一篇文章 《关于 OkHttp 和 Retrofit 的使用,你需要注意的点》 讲到了 拦截器中抛出非 IOException
异常而且使用了 enqueue 进行异步请求的时候 OkHttp 会直接使 App crash(使用 execute 方法进行同步请求的时候如果没有捕获非 IOException
异常的话也是一样的),那么 Callback
的 onFailure 方法和 onResponse 方法究竟会在什么时候回调呢?本节咱们就来看看 OkHttp Callback
调用的源码,一探究竟!
添加依赖
// OkHttp 框架:https://github.com/square/okhttp
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
简单使用
老样子,咱们先写一个最简单的 OkHttp 调用。
private val mClient = OkHttpClient.Builder()
.build()
fun okHttpTest() {
val request = Request.Builder()
.url("https://www.baidu.com/")
.build()
mClient.newCall(request)
.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
e.printStackTrace()
}
@Throws(IOException::class)
override fun onResponse(call: Call, response: Response) {
println("okHttpExceptionTest:response is ${response.body?.string()}")
}
})
}
然后,我们按住 Ctrl 并点击 enqueue 方法查看在哪里调用了这个 Callback。
咦,居然是个 Call
接口,那行吧。咱们先看看这个 Call
接口是个啥玩意儿。我们想看这个 Call
接口是个啥之前,先看看它是怎么来的吧。
按住 Ctrl 然后鼠标点击 enqueue 方法之前的 newCall 方法。
然后,我们尝试搜索 enqueue 这个方法,看看在哪里实现的。
很明显,刚刚我们 new 的 Callback 被传入了 AsyncCall
这个类的构造方法中,那行呗,咱们继续往下跟。
这个时候,我们尝试搜索一下 responseCallback 这个变量的 onFailure 方法在 AsyncCall
中的调用。
小技巧:在这里面如果搜不到它的调用的话,那么这个变量一定是被传递给另外一个类了。
这里,我们可以看到 onFailure 方法在这个类里一共有 3 处调用,那么我们接下来看看剩下两处调用在哪里。
以上就是 onFailure 回调方法的全部调用啦,看过 上一篇文章 的同学可能会注意到这些调用传入的全部都是 IOException
!
既然 onFailure 回调看完了,如法炮制,那我们再看看 onResponse 方法的调用吧。
这里我们可以看到,回调 onResponse 方法的时候首先捕获了 IOException
这个异常,然后回调到 onFailure 方法,如果是非 IOException
的话,则会先调用 cancel 方法取消网络请求的调用,然后将该异常直接 throw 抛出。
我们看到调用 onResponse 之前先调用了 getResponseWithInterceptorChain 方法,从方法名翻译过来就是:使用拦截器链获得响应。
既然如此,那我们再去看看 getResponseWithInterceptorChain 方法里面的实现吧。
可以看到,OkHttp 通过 client 的 interceptors 这个 get 方法拿到了一堆拦截器然后传给 RealInterceptorChain
这个 真正的拦截器链 进行调用处理。
那么,这个 client 变量是个啥呢?
还记得我们最开始想看 newCall 方法的时候创建了一个 RealCall
对象的实例吗?第一个参数传入了 "this" 。没错!这个 "this" 正是我们自己最开始创建的 "mClient" !
这个时候我们就能从源码调用的层面解释为啥在拦截器中抛出非 IOException
异常的时候会导致 APP crash 了。
总结
在看源码时如果遇到返回的是接口的情况,我们应该先去看它是怎么被创建(获取到)的,然后去看它的具体实现。
如果对你有帮助的话,欢迎一键三连+关注哦~