OkHttp源码分析系列(上)流程篇

1,014 阅读5分钟

引言

okHttp可以说是Android开发中高频使用的框架之一,不管是解决项目中遇到的问题,还是面试时面试官问到的问题,都需要对源码有一个基本的认识,因此解读一下源码是本文的初衷。本文基于如下版本的OKHttp分析的源码:

implementation 'com.squareup.okhttp3:okhttp:3.10.0'

OkHttp基本使用

okhttp基本使用如下图:

image.png

  1. 第一步创建OkHttpClient。
  2. 第二步创建Request。
  3. 第三步创建Call。
  4. 第四部执行Call的触发网络请求方法,分为同步和异步。 经过以上四个步骤,一个简单的网络请求就完成了。

创建OkHttpClient源码分析

接下来分析一下第一步的源码:

image.png

可以看到,我们调用的构造方法,里面调用了一个builder。接下来我们看一下这个Builder。

image.png 可以看到Builder的构造方法里面,做了很多初始化相关的工作,初始化了很多的内容,比如Dispathcher,EventListener,ConnectionPool等。

创建Request源码分析

接下来分析第二步创建Requset的源码:

image.png Request这个类,结构比较简单,主要是构建一个请求,里面是一些请求的相关字段,例如请求地址,请求类型,请求头,请求体等。也是通过Builder模式创建的。

创建Call源码分析

接下来我们看一下第三步创建Call的源码:

image.png 可以看到,通过OkHttpClient调用了他的newCall方法,这个方法,实际是由RealCall.newRealCall返回的Call对象。这个方法传入了OkHttpClient对象,Request对象。那我们接着往下看Call是如何被创建的。

image.png 首先可以看到,newRealCall里面做了哪些操作,创建了一个RealCall对象,在RealCall的构造方法里面,初始化了client,request和retryinterceptor。然后返回了这个RealCall对象。看到这里可能有人会有疑问,我要的不是Call对象吗,怎么返回了RealCall。那我们看一下最上面一行的代码,可以看到,RealCall实现了Call的接口。以上就是Call的一个创建流程。

执行网络请求流程

接下来我们看一下第四步真正执行网络请求的位置: call触发的异步方法真正实现的地方在RealCall中:

image.png 这个方法里面的核心代码在最后一行:

client.dispatcher().enqueue(new AsyncCall(responseCallback));

这里也是我们网络请求真正开始的地方。通过client对象调用了client初始化的时候创建的dispatcher,然后调用的dispatcher的enqueue方法,传入了一个AsyncCall对象。接下来我们看一下enqueue方法具体内容:

image.png 这个方法是Dispatcher里面的,先简单介绍一下这几个变量。

  1. runningAsyncCalls 运行中的异步call,是一个ArrayDeque。
  2. maxRequests 最大运行中的请求数量,默认值为64,可以手动修改,有提供set/get方法。
  3. maxRequestsPerHost同一个Host的最大请求数量,默认值为5,也可以手动修改,有提供set/get方法。
  4. readyAsyncCalls准备中的异步队列,也是一个ArrayDeque。

介绍完了这几个变量,接下来讲一下这个方法干了哪些事情。 首先方法内部是一个if 和else语句,if这里判断的条件为:当前运行中的call是否小于最大请求数量的限制,当前同一个hosts的请求是否小于同一个hosts的最大请求数量,如果都满足条件的话,则把当前的call加入到runningcalls中,然后通过线程池,执行AsyncCall。如果当前请求数量超过最大值或者单条hosts请求超过单条最大值,那么则把Call加入到readyCalls中。

接下来我们看一下Dispatcher的executorService方法。

image.png 在这个加锁的方法中,创建了一个线程池,注意线程池使用的队列,这是一个同步队列。这个线程池没有核心线程,只有非核心线程,超时时间为60S。通过创建的线程池的execute方法,执行了AsyncCall这个请求。

接下来我们看一下AsyncCall这个类是干什么的,做了哪些工作。

image.png 通过代码可以看到,主要的内容都在execute()方法中,可以看到这是一个非常经典的try+catch+finally的结构,接下来分析一下这个方法做了哪些工作。

execute()方法主要部分有两个: 1.try中的这部分。 2.finally中的部分。

先看一下try中代码内容,主要有两步:1.获取response。2.触发Callback回调。 那么网络请求的重点,显然在第一步了,如何获取到的response?。接下来我们看一下这个getResponse的方法,看一下具体是一个什么样的过程。

image.png 这里就是OkHttp的拦截器和拦截器连创建和执行的位置了。 先看拦截器这里,1.先添加的是client的拦截器List,这个List是你创建client的时候,如果有自定义的拦截器,那么就回首先加进来,如果没有的话List长度为0。2.第二个加进来的为retry拦截器。3.第三个为Bridge拦截器。4.第四个为Cache拦截器。5.Connect拦截器。6.为network拦截器。7.为CallServer拦截器。

然后再看责任链,创建了一个责任链,通过第一次构造传入的interceptors,每次调用proceed方法时,index+1,来取下一个拦截器,然后再次通过责任链调用,直到调用到最后一个拦截器,返回response对象,整个请求的流程就结束了。具体代码如下图:

image.png

image.png

image.png 通过这两张图可以看到,除了最后的CallServer拦截器没有执行proceed方法,其他拦截器return 都是这个方法的返回结果。

再看一下finally中的代码。主要是调用了promoteCalls方法,把readyCalls中的AsyncCall加到runningCalls中,然后通过线程池执行。

image.png

结束语

OkHttp流程篇,到这里就讲的差不多了,这个系列的下一篇文章会详细的讲一下各大拦截器的作用,以及真正的网络请求是在哪里发送的。

转载请注明出处,微信公众号的转载请联系本人授权。