OkHttp可以说是Android开发中使用最广泛的网络框架,从Android4.4开始HttpURLConnection的底层实现也被谷歌替换成OkHttp
下面先来看看okhttp同步请求的简单使用
我们可以看到,okhttp请求中最少只需要接触到OkHttpClient,Request,Call,Response,剩下的都交由框架内部进行处理。
所有的逻辑大都集中在拦截器中,但在进入拦截器之前还需要依靠分发器来调配请求任务。
其中,分发器负责内部维护队列与线程池,完成请求调配,也就是说管理请求任务什么时候被执行,拦截器负责完成整个请求过程。
咱们先来看跟Dispatcher有关的源码,通过异步请求调用call身上的enqueue方法。
可以看到,首先调用了一个内置锁,锁的对象是当前RealCall的实例,锁内部显然是一个限制,限制获取到的call,如果对它进行了一次enqueue方法的调用,在进行一次调用时会抛出异常,所以说,call只能使用一次,如果需要再次使用,则需要调用call.clone()方法。
继续往下看,eventListener是一个监听,可以对请求开始,结束等状态进行监听。
最后一行中client,是指OkHttpClient,dispatcher()获得的是client身上的分发器,调用上面的enqueue方法,并传入一个AsyncCall,AsyncCall可以看成当前的请求任务。那接下来我们进入分发起的代码。
首先我们看一下分发其中有哪些成员。
我们可以看到,类中有三个队列,
runningAsyncCalls,正在执行的异步请求队列
readyAsyncCalls,等待执行的异步请求队列
runningSyncCalls,正在执行的同步请求队列
我们可以想到当意不请求任务进入到enqueue方法中后,会被放入runningAsyncCalls或readyAsyncCalls,那么如何决定放入哪个队列呢?read队列中的任务什么时候才能进入running队列呢?我们继续来看源码
可以看到,正在执行的异步请求个数小于maxRequest, maxRequest默认为64,防止创建过多的线程池。再看下一个条件,
这是判断访问的域名是否相同,访问相同域名的数量不大于maxRequestsPerHost,默认为5。
那么,我们的异步请求放入running队列的条件就是 ;
1.正在执行的异步请求个数小于64.
2.与这次访问相同域名的请求个数不大于5.
之后会调用线程池,将当前任务交给线程池。我们再看回AsyncCall,AsyncCall最终集成于Runnable,Runnable的run方法中执行了一个execute的抽象方法。
所以,线程池会调用线程中的execute方法。
execute上来就跑了拦截器,然后就得到了response,这里也可以看出,拦截器里处理了整个请求的发送与接收,拦截器咱们下一篇再说,先继续看源码,不管这个请求成功与否,都会执行finally中的分发器的finished方法,跳到finished中
既然完成了请求,首先把当前call从running队列中remove掉,之后如果promoreCalls为true,执行了 promoreCalls方法
promoreCalls就是尝试将ready队列中的成员放入running队列中,只要满足与这次访问相同域名的请求个数不大于5,就可以加入running队列,如果大于5,那就走next方法判断下一个。这样循环往复就是分发器的功能。