本文会介绍现在比较主流的几个网络库 Retrofit、OkHttp、Volley ,介绍主要从源码出发,介绍这些网络库的设计和内部实现。
Retrofit
Retrofit 是在 OkHttp 的基础上进行的封装,这里不详细介绍了,有兴趣的可以直接看 拆 Retrofit 。
OkHttp
基本用例
OkHttpClientclient = newOkHttpClient();
Requestrequest = newRequest.Builder().url(url).build();
Responseresponse = client.newCall(request).execute();
我们看到主要逻辑就是 client.newCall(request).execute() ,所以我们看下 RealCall 的 execute 方法。
同步网络请求 RealCall#execute
主要做了 4 件事:
1.检查 call 是否已经执行;
2.执行 client.dispatcher().executed(this) ,我们看下 Dispatcher#executed() 方法,其实什么都没做,就是把 call 放到 runningSyncCalls 中。
3.执行 getResponseWithInterceptorChain() 获取 Response。
4.最后执行 client.dispatcher().finished(this); 告诉 Dispatcher 执行完成。
Interceptor 是 OkHttp 最核心的一个东西,不要误以为它只负责拦截请求进行一些额外的处理(例如 cookie),实际上它把实际的网络请求、缓存、透明压缩等功能都统一了起来,每一个功能都只是一个 Interceptor,它们再连接成一个 Interceptor.Chain,环环相扣,最终圆满完成一次网络请求。
异步网络请求 RealCall#enqueue
这里我们就能看到 dispatcher 在异步执行时发挥的作用了,如果当前还能执行一个并发请求,那就立即执行,否则加入 readyAsyncCalls 队列,而正在执行的请求执行完毕之后,会调用promoteCalls() 函数,来把 readyAsyncCalls 队列中的 AsyncCall “提升” 为 runningAsyncCalls,并开始执行。
这里的 AsyncCall 是 RealCall 的一个内部类,它实现了 Runnable,所以可以被提交到 ExecutorService 上执行,而它在执行时会调用 getResponseWithInterceptorChain() 函数,并把结果通过 responseCallback 传递给上层使用者。
这样看来,同步请求和异步请求的原理是一样的,都是在 getResponseWithInterceptorChain() 函数中通过 Interceptor 链条来实现的网络请求逻辑,而异步则是通过 ExecutorService 实现。
Volley
RequestQueue
在聊 RequestQueue 之前,RequestQueue 中有几个成员变量我们需要着重介绍下:
mWaitingRequests :如果已经有 Request 在 CacheQueue 中则把 Request 放到 mWaitingRequests 中。
mCurrentRequests:保存当前所有的 Request。
mCacheQueue:CacheDispatcher 执行的相关请求。
mNetworkQueue:NetworkDispatcher 执行的相关请求。
CacheDispatcher:Cache Request 执行的线程。
NetworkDispatcher[]:Request 执行线程,size 默认大小是 4。
mDelivery:Response 分发器。
首先我们先看 RequestQueue#add(Request request) 方法
首先把 Request 放到 mCurrentRequests 中,然后看 Request 是否是 Cacheable 的,如果不是就把 Request 放到 mNetworkQueue 中并结束此流程。否则继续往下走,查看 mWaitingRequests 中是否包含此 Request 的 CacheKey,如果包含说明此 Request 已经在 mCacheQueue 中,把 Request 放到 mWaitingRequests 中,流程结束;否则把 Request 放到 mCacheQueue 中。
下边我们看下 RequestQueue#start() 方法
我们看到 start() 方法其实很简单,就是按顺序分别执行 CacheDispatcher 和 NetworkDispatcher 的 start() 方法。那么我们就具体看下 CacheDispatcher 和 NetworkDispatcher 。
CacheDispatcher
CacheDispatcher extends Thread ,所以我们直接来看 CacheDispatcher#run() 。
首先 run() 方法内是一个 while(true) 循环,不断从 BlockingQueue
在 while 循环内首先检查 Request 是否已经 cancel ,如果已经 cancel 则结束一次循环否则继续向下执行;然后检查 Request 是否有 cache ,如果没有则把此 Request 放入 NetworkQueue 并结束一次循环,否则继续执行;检查 cache 是否过期,如果过期则把此 Request 放入NetworkQueue 并结束一次循环,否则继续执行;最后检查是否该刷新 cache,如果不该刷新则 delivery 此 cache response 并结束一次循环,否则 delivery 此 cache response 并把此 Request 放入 NetworkQueue 。
NetworkDispatcher
NetworkDispatcher extends Thread ,所以我们直接来看 NetworkDispatcher#run() 。
首先 run() 方法内是一个 while(true) 循环,不断从 BlockingQueue
在 while 循环内首先检查 Request 是否已经 cancel ,如果已经 cancel 则结束一次循环否则继续向下执行;然后执行网络请求并得到 Response ,然后检查此 Response 是否 304 并且已经 delivery ,如果是则结束一次循环否则继续向下执行;然后检查此 Request 是否是 CacheRequest ,如果是则刷新缓存,而且此 Request 会有两次回调;最后 delivery 此 Response 。
最后我们再来看下 RequestQueue#finish() 方法。
RequestQueue#finish()
首先从 mCurrentRequests remove 此 request,然后查看 mWaitingRequests 中是否存在和此 request cacheKey 相同的 request,如果存在则把这些 requests 取出放到 mCacheQueue 中。