网络库介绍

本文会介绍现在比较主流的几个网络库 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

网络库介绍_第1张图片
execute()

主要做了 4 件事:

1.检查 call 是否已经执行;

2.执行 client.dispatcher().executed(this) ,我们看下 Dispatcher#executed() 方法,其实什么都没做,就是把 call 放到 runningSyncCalls 中。

3.执行 getResponseWithInterceptorChain() 获取 Response。

4.最后执行 client.dispatcher().finished(this); 告诉 Dispatcher 执行完成。

网络库介绍_第2张图片
getResponseWithInterceptorChain()

Interceptor 是 OkHttp 最核心的一个东西,不要误以为它只负责拦截请求进行一些额外的处理(例如 cookie),实际上它把实际的网络请求、缓存、透明压缩等功能都统一了起来,每一个功能都只是一个 Interceptor,它们再连接成一个 Interceptor.Chain,环环相扣,最终圆满完成一次网络请求。

异步网络请求 RealCall#enqueue

网络库介绍_第3张图片
RealCall#enqueue()
网络库介绍_第4张图片
Dispatcher#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) 方法

网络库介绍_第5张图片
add(Request request)

首先把 Request 放到 mCurrentRequests 中,然后看 Request 是否是 Cacheable 的,如果不是就把  Request 放到 mNetworkQueue 中并结束此流程。否则继续往下走,查看 mWaitingRequests 中是否包含此 Request 的 CacheKey,如果包含说明此 Request 已经在 mCacheQueue 中,把 Request 放到 mWaitingRequests 中,流程结束;否则把 Request 放到 mCacheQueue 中。

下边我们看下 RequestQueue#start(方法

网络库介绍_第6张图片
start()

我们看到 start() 方法其实很简单,就是按顺序分别执行 CacheDispatcher NetworkDispatcher start() 方法。那么我们就具体看下 CacheDispatcher 和 NetworkDispatcher

CacheDispatcher

CacheDispatcher extends Thread ,所以我们直接来看 CacheDispatcher#run() 。

网络库介绍_第7张图片
run()

首先 run() 方法内是一个 while(true) 循环,不断从 BlockingQueue> mCacheQueueRequest

while 循环内首先检查 Request 是否已经 cancel ,如果已经 cancel 则结束一次循环否则继续向下执行;然后检查 Request 是否有 cache ,如果没有则把此 Request 放入 NetworkQueue 并结束一次循环,否则继续执行;检查 cache 是否过期,如果过期则把此 Request 放入NetworkQueue 并结束一次循环,否则继续执行;最后检查是否该刷新 cache,如果不该刷新则 deliverycache response 并结束一次循环,否则 deliverycache response 并把此 Request 放入 NetworkQueue 。

NetworkDispatcher

NetworkDispatcher extends Thread ,所以我们直接来看 NetworkDispatcher#run() 。

网络库介绍_第8张图片
run()

首先 run() 方法内是一个 while(true) 循环,不断从 BlockingQueue> mQueue 取 Request

在 while 循环内首先检查 Request 是否已经 cancel ,如果已经 cancel 则结束一次循环否则继续向下执行;然后执行网络请求并得到 Response ,然后检查此 Response 是否 304 并且已经 delivery ,如果是则结束一次循环否则继续向下执行;然后检查此 Request 是否是 CacheRequest ,如果是则刷新缓存,而且此 Request 会有两次回调;最后 deliveryResponse

最后我们再来看下 RequestQueue#finish() 方法。

RequestQueue#finish()

网络库介绍_第9张图片
finish()

首先从 mCurrentRequests remove request,然后查看 mWaitingRequests 中是否存在和此 request cacheKey 相同的 request,如果存在则把这些 requests 取出放到 mCacheQueue

你可能感兴趣的:(网络库介绍)