请求队列RequestQueue是一个拥有分发器线程池的请求分发队列。把一个请求入队,那么可能会执行缓存分发器队列里面的请求,也可能直接执行网络分发器队列里面的请求。如果请求有存在在缓存分发器队列中,那么根据特定条件来执行(到底如何执行请求的,请看上一篇博客Volley源码阅读之缓存分发器(CacheDispatcher)工作原理)。
下面,我们先来看RequestQueue的几个成员变量以及作用:
/**请求的集结区(有一份副本在执行)*/
private final Map<String, Queue<Request<?>>> mWaitingRequests =
new HashMap<String, Queue<Request<?>>>();
/**所有正在被当前请求队列处理的请求的集合,任何一个在队列中等待或者正在被这个队列处理的请求都会加入到此集结区*/
private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
/** 缓存级别的请求队列*/
private final PriorityBlockingQueue<Request<?>> mCacheQueue =
new PriorityBlockingQueue<Request<?>>();
/** 直接请求网络的请求的队列*/
private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
new PriorityBlockingQueue<Request<?>>();
/** 网络分发器池的默认的大小*/
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
/** 回调和存储响应*/
private final Cache mCache;
/** 执行网络分发器发来的请求*/
private final Network mNetwork;
/**响应传递 */
private final ResponseDelivery mDelivery;
/** 网络分发器 */
private NetworkDispatcher[] mDispatchers;
/** 缓存分发器 */
private CacheDispatcher mCacheDispatcher;
......
创建出RequestQueue的对象来要调用start方法才能让请求队列工作。start方法是启动网络分发器后者缓存分发器的方法。现在我们先来看看请求队列RequestQueue的start()方法。
public void start() {
stop(); //关闭所有正在执行的分发器
// 创建缓存分发器并启动它
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// 根据分发池大小来创建网络分发器池,池的大小是在创建RequestQueue的时候就指定的了
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
由以上源码的分析可以知道,RequestQueue开始分发请求的时候,首先会从缓存中获取数据,如果没有想要的数据,那么就会从网络中获取。从网络中获取使用了池。
请求队列RequestQueue还有一个重要的方法,就是add方法:
public <T> Request<T> add(Request<T> request) {
// 加入当前请求集合
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// 根据添加顺序来执行请求
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
// 如果请求不需要缓存,直接把请求添加进网络分发器
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
// 如果已经有相同的缓存key(请求的url)的请求,把请求加入集结区
synchronized (mWaitingRequests) {
String cacheKey = request.getCacheKey();
if (mWaitingRequests.containsKey(cacheKey)) {
Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
if (stagedRequests == null) {
stagedRequests = new LinkedList<Request<?>>();
}
stagedRequests.add(request);
mWaitingRequests.put(cacheKey, stagedRequests);
if (VolleyLog.DEBUG) {
VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
}
} else {
//null值代表开始有一个cacheKey请求在执行中
mWaitingRequests.put(cacheKey, null);
//添加缓存
mCacheQueue.add(request);
}
return request;
}
}
可以知道,add方法添加请求的时候,如果请求不需要缓存那么直接交给网络分发器处理就可以了。如果需要缓存,首先判断集结区是否已经有这个请求存在。如果存在,则重设这个请求的值(Map结构中相同的key的value值会覆盖,mWaitingRequests是HashMap集合。),如果不存在那么就往缓存分发器添加这个请求。