OkHttp
是当下Android使用最频繁的网络请求框架,由Square
公司开源。 Google在Android4.4以后开始将源码中的HttpURLConnection
底层实现替换为0KHttp
,同时现在流行的Retrofit框架底层同样是使用OKHttp的。
我们将了解下OKHttp的源码,但是不同的版本源码会有一些差异,等下我会大概说一下3.10.0
和4.9.3
版本的不同之处
大家应该都用过OKHttp,只是你们自己可能都不知道,因为我们项目中经常使用的是像Retrofit这样的网络框架,但其实Retrofit是基于OKHttp进行的再次封装,将返回的结果等进行了一些更加人性化的封装,更便于我们开发使用。
//1
OkHttpClient okHttpClient = new OkHttpClient();
//2
Request request = new Request.Builder()
.url("www.baidu.com")
.build();
//3
Call call = okHttpClient.newCall(request);
//4异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
}
});
//或者同步请求
try {
Response response = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
其实看了这个发现OKHttp重要的还是分发器和拦截器,那么下面我们就来讲一下什么是分发器、拦截器,他们有什么用,是怎么工作的。
Dispatcher
分发器就是来调配请求任务的,内部会包含一个线程池(异步任务才会用到)。可以在创建 OkHttpClient
时,传递我们 自己定义的线程池来创建分发器。下面我们跟着源码追一下吧,我们看异步的,同步的可以自行查看比较简单。
③进到RealCall
的enqueue
中,发现要去到dispatcher
的enqueue
runningAsyncCalls
readyAsyncCalls
running
当前任务数小于规定的max
值(默认64)(考虑到手机压力)
且running
队列里面正在访问的host和当前host相同的任务不能超过5个(减少服务器压力)
当正在执行的任务未超过最大限制64,同时 runningCallsForHost(call) < maxRequestsPerHost
同一Host的请求 不超过5个,则会添加到正在执行队列,同时提交给线程池直接执行。否则先加入等待队列。
但他没有run
方法,而且继承的也不是Runable
对象,我们看下NamedRunnable
到底是个什么东西
⑥
原来如此,有个抽象的execute
方法在run里面执行,所以线程池就会执行AsyncCall
的execute
方法了
⑦
try和catch先不管看到finally,会执行finished
方法
⑧
将这个任务从runningAsyncCalls
中移除,然后命中if语句,进入promoteCalls
⑨
遍历readyAsyncCalls
中的任务,根据判断的规则将任务加入到runningAsyncCalls
中然后调用线程池进行执行。
现在我们想想是不是分发器我们已经走完一遍了?不是要从分发器到拦截器吗?根据我们上面的整体流程图应该是这样的,那我们什么时候进入到拦截器的呢?其实是在
execute
方法的时候:
④来到dispatcher
的enqueue
方法中
这里已经是不一样的了,这里不再判断,而是直接将任务加入到readyAsyncCalls
中,然后调用promoteAndExecute
⑥
遍历,然后根据上面相同的条件,是否将任务加入到runningAsyncCalls
中,另外多了一个队列executableCalls
⑦
然后遍历执行executableCalls
队列中的任务
⑧
⑨还是要来到dispatcher
的finished
方法
这个版本的源码我没有详细讲解,但是你们应该都看得懂。跟3.10.0版本的有一些区别,但是也有很多相似的地方
这里由于篇幅,不再详细说明,这里线程池的队列用的无界队列SynchronousQueue
核心线程数为0
,最大线程数为Integer.MAX_VALUE
实现了一个最大并发量的线程池