用了一段时间的OkHttp库,版本3.4.1。 最近总算有时间看看源码了, 主要是根2.4.0版本的区别;
看了篇讲OkHttp的博客http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0326/2643.html , 3.4.1版本有很大变化, 没有HttpClient了。
对于互联网app在使用okhttp时, 一般都是实例化一个Request后交给OkHttpClient。 OkHttpClient通过Dispatcher类(做调度逻辑的, 可以理解为司令的作用)从队列(针对异步方式)里取出请求(Call是一次请求/返回的执行单元),从内存或服务器取数据,并加入到执行队列runningAsyncCalls里, 如果超过限制(做多并发64个请求或相同host的5个请求)则加入到待执行队列readyAsyncCalls; 对于同步方式则执行,并放到runningSyncCalls中管理;
从上图也可以看出OkHttp支持缓存, 即无网络请求下也能拿到接口数据(从上次成功的文件缓存里);OkHttp也使用了线程池, 对使用OkHttp的app来说就不要再创建线程或线程池使用OkHttp了。 多线程并发下载/上传文件的实现方法可以我的上篇博客。
我只画了一部分类图, 要了解OkHttp的调度必须要看Dispather.java, 这个类就是OkHttp的大管家, 它是管着干活的Call类。 Dispatcher.java里有个成员变量executeService, 所有异步请求都是在这个线程池里执行的, 在下面的时序图里Dispatcher之前的时序是同步执行的, Dispatcher后的流程都是在子线程执行的。
ConnectionPool.java也有个线程池变量executor, 从类名看出它是用来复用tcp连接的, 有点像长连接, 在文章头那篇引用博客里讲到了。
在OkHttp框架里用到线程池的就是Dispatcher和ConnectionPool类。
上图是异步请求的时序图, 其中最关键的函数是RealCall类里的getResponseWithInterceptorChain, 默认有5个interceptor对象。
private Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors()); //app设置的自定义拦截器,比如说每个接口要判断是否已登录
interceptors.add(retryAndFollowUpInterceptor); //第1个
interceptors.add(new BridgeInterceptor(client.cookieJar())); //第2个
interceptors.add(new CacheInterceptor(client.internalCache())); //缓存拦截器,第3个
interceptors.add(new ConnectInterceptor(client)); //连接池, 复用连接。第4个
if (!retryAndFollowUpInterceptor.isForWebSocket()) {
interceptors.addAll(client.networkInterceptors());
}
interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket())); //第5个
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
可以看出每个请求最终都执行到接口Interceptor的实现类中, 为了看明白chain.proceed(originalRequest)的执行过程, 我注释了interceptors.add(new CallServerInterceptor(
retryAndFollowUpInterceptor.isForWebSocket()));这行代码, 然后执行会崩溃并打印堆栈, 这样就能看到这4/5个拦截器的执行时序了。
java.lang.AssertionError
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:72)
at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:109)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:186)
at okhttp3.RealCall.access$100(RealCall.java:35)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:134)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818
从上面堆栈看出OkHttp是使用拦截器做各种逻辑的, 通过实现接口类Interceptor的intercept函数来做各种功能;
public interface Interceptor { Response intercept(Chain chain) throws IOException; interface Chain { Request request(); Response proceed(Request request) throws IOException; Connection connection(); } }
下图是调试步骤截图:
我的微信公众号, 欢迎关注, 让我们一起成长