前言
最近一个项目用到Volley
处理网络请求,于是借这个机会研究下源码。Volley
是2013 Google I/O上发布的网络请求框架,适合小而频繁的网络通信,源码发布在https://android.googlesource.com/platform/frameworks/volley,同时推荐GitHub上的一个非官方镜像项目https://github.com/mcxiaoke/android-volley。
简介
作为一款优秀的框架,Volley
具有很高的扩展性。其基本架构是面向接口编程的,这部分代码位于com.android.volley
,同时也给出了默认的实现,这部分代码位于com.android.volley.toolbox
,如果需要扩展,只需要自己实现com.android.volley.toolbox
包中的类即可。
使用
作为铺垫,先hello world一下Volley
的使用。
Step 1:
com.android.toolbox.volley
类有4个重载的静态方法,用于构建RequestQueue
:
public static RequestQueue newRequestQueue(Context context);
public static RequestQueue newRequestQueue(Context context, HttpStack stack);
public static RequestQueue newRequestQueue(Context context, int maxDiskCacheBytes);
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes);
这4个重载的方法会调用RequestQueue
的构造函数及其start()
方法,使相关的Dispatch线程开始工作。
Step 2:
有了RequestQueue
之后,我们只需要调用如下方法向请求队列中加入请求即可发起网络请求:
public <T> Request<T> RequestQueue.add(Request<T> request);
好了,这只是个简单的认识,接下来开始详细分析。
核心类
简单列出框架的核心类,大致被我分为以下4部分:
Request
Request<T>
:代表一个请求(抽象类)
RequestQueue
:存放各种状态下的Request
,不要被名字迷惑,它不是一个简单的Queue
,而是包含两个Queue
,一个Set
,一个Map
Response
Response<T>
:代表一个请求结果
ResponseDelivery
:处理Response
(接口)
ExecutorDelivery
:这是ResponseDelivery
的默认实现Cache
Cache
:负责缓存的存取、更新等(接口)
Cache$Entry
:缓存中保存的内容(静态内部类)
CacheDispatcher
:缓存分发线程Network
Network
:负责发起网络请求(接口)
NetworkResponse
:网络请求返回的结果
NetworkDispatcher
:网络请求分发线程
基本流程
有了核心类,就可以给出大致的工作流程了。
请求(Request)
Request<T>
它是个抽象类,保存了请求的类型,URL,参数,header,body,优先级,响应错误处理回调接口等,泛型参数<T>
表示该请求返回的数据类型。Volley
中给出了StringRequest
,JsonRequest
,ImageRequest
三种默认实现,我们也可以按需要给出自定义的实现。
Request<T>
有两个重要的抽象方法,它们定义了请求完成后的处理方式:
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
abstract protected void deliverResponse(T response);
RequestQueue
RequestQueue
维护了如下4个集合,表示了整个框架中各种状态下的Request
。
PriorityBlockingQueue<Request<?>> mCacheQueue
:
缓存请求队列PriorityBlockingQueue<Request<?>> mNetworkQueue
:
网络请求队列Set<Request<?>> mCurrentRequests
:
正在执行中的网络请求,文档中用了“in flight”这个词,很贴切Map<String, Queue<Request<?>>> mWaitingRequests
:
等待请求的集合,如果一个请求正在被处理(即in flight)并且可以被缓存,则后续的具有相同url的请求,将进入此等待队列
响应(Response)
NetworkResponse
这是网络请求返回的原始结果,包括statusCode
,header
,结果主体byte[] data
等。
Response<T>
它保存了加工后的请求结果<T> result
,对应的要放入缓存的内容Cache.Entry cacheEntry
,错误VolleyError error
。前面讲Request
中提到的Request.parseNetworkResponse()
方法会在工作线程中将原始的NetworkResponse
转化为Response<T>
,并交给ResponseDelivery
处理。
ResponseDelivery
这是个接口,它只有三个方法,负责处理最终的结果(或错误):
public void postResponse(Request<?> request, Response<?> response);
public void postResponse(Request<?> request, Response<?> response, Runnable runnable);
public void postError(Request<?> request, VolleyError error);
ExecutorDelivery
这是Volley
里给出的ResponseDelivery
的默认实现,它的工作流程是这样的:
ExecutorDelivery
的构造函数传入的参数中通过new Handler(Looper.getMainLooper())
获取了主线程的Handler
。postResponse()
和postError()
方法会根据传入的Request
,Response
,Runnable
,VolleyError
等参数,构造出一个新的Runnable
对象,新的Runnable
包含了主线程所要做的全部回调工作。- 调用
Handler.post(Runnable runnable)
将上一步构造出来的新的Runnable
发送给主线程Looper
的MessageQueue
,Volley
的任务也就完成了。
缓存(Cache)
Cache
这是表示缓存的接口,提供了get()
,put()
,remove()
等基本操作,它包含一个静态内部类Cache$Entry
,包括数据主体byte[] data
,以及与过期策略有关的时间期限等内容,缓存与外界的读写操作都是以Entry
为单位进行的。
DiskBasedCache
这是Volley
中Cache
接口的默认实现。
- 定义了
DiskBasedCache$CacheHeader
内部类,用于存储对应请求的header
,用一个基于访问顺序accessOrder(而非插入顺序insertOrder)的LinkedHashMap<String, CacheHeader>
存储这些header
,而缓存的主体则是存放在File
中,文件名通过CacheHeader
的key
计算得到,key
和File
一一对应。 - 写缓存时,将
Entry
中的数据主体通过Stream
写入File
,将其他内容放入CacheHeader
。 - 读缓存时,
Entry
的数据主体通过Stream
从File
中读入,其他内容从CacheHeader
读入。
CacheDispatcher
- 这是个线程,继承了
Thread
,每个RequestQueue
对应一个CacheDispatcher
,它的run()
方法会不断从RequestQueue
的缓存请求队列mCacheQueue<Request<?>>
中取出Request
进行处理。 - 如果
mCache
中可以找到对应的缓存结果并且没有过期,则取出缓存,构造对应的Response
,并将Request
和Response
一起交给ResponseDelivery
处理即可。 - 如果
mCache
中找不到对应的缓存结果或者过期了,则将该Request
加入到网络请求队列mNetworkQueue<Request<?>>
中,等待发起网络请求。
网络(Network)
Network
这是网络请求接口,只有一个方法,用于发起请求:
public NetworkResponse performRequest(Request<?> request) throws VolleyError;
BasicNetwork
这是Volley
中Network
接口的默认实现。performRequest()
方法中会调用HttpStack
发起网络请求,具体代码略多,仍有待研究。
NetworkDispatcher
- 这是个线程,继承了
Thread
,每个RequestQueue
对应多个(默认4个)NetworkDispatcher
,它的run()
方法会不断从RequestQueue
的网络请求队列mNetworkQueue<Request<?>>
中取出Request
进行处理。 - 对于取出的每个
Request
,调用mNetwork
发起网络请求,请求成功后,将得到的结果NetworkResponse
转化为Response<T>
,交给ResponseDelivery
处理。 - 如果该结果需要缓存,则调用
mCache.put()
写缓存。
总结
// TODO 此处应有流程图一张,懒得画了,改天再补。