您的位置:首页 > 理论基础 > 计算机网络

Android网络框架volley学习(六)调度器CacheDispatcher简析

2018-01-25 18:00 471 查看
在前面的分析文章中,我们了解到,当发起一个请求时,首先加入到请求队列中,请求队列中是如何工作的呢?它会首先去缓存队列中取,如果不符合的话另开网络线程去执行这个请求操作。

源码路径RequestQueue#start

/**
* Starts the dispatchers in this queue.
*/
public void start() {
// Make sure any currently running dispatchers are stopped.
stop();

//缓存线程工作
// Create the cache dispatcher and start it.
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();

//默认有4个网络线程工作
// Create network dispatchers (and corresponding threads) up to the pool size.
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}


本篇文章我们就来详细了解一下两个线程调度器NetworkDispatcher和CacheDispatcher是如何工作的。

CacheDispatcher

顾名思义,这是一个缓存调度线程,用于处理走缓存的请求。首先看下它的变量。

成员变量

/** 缓存请求队列 */
private final BlockingQueue<Request<?>> mCacheQueue;

/** 网络请求队列 */
private final BlockingQueue<Request<?>> mNetworkQueue;

/** 缓存类接口 */
private final Cache mCache;

/** 返回处理请求的结果 */
private final ResponseDelivery mDelivery;

/** 退出线程 */
private volatile boolean mQuit = false;

/** 等待请求管理类或者处理重复请求的管理类*/
private final WaitingRequestManager mWaitingRequestManager;


接着进行初始化操作。

既然CacheDispatcher是一个线程,那么接着我们就来看下它的run方法。

@Override
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");

//设置优先级,略低于正常线程的优先级
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

//缓存线程初始化
mCache.initialize();

//循环工作
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
}
}
}


这里面没有什么大动作,我们来看下里面的processRequest方法是干嘛的。由于这个方法太长,我们一步一步分析。

首先从缓存队列中取出请求,判断是否已经取消了。

final Request<?> request = mCacheQueue.take();
request.addMarker("cache-queue-take");

// If the request has been canceled, don't bother dispatching it.
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
return;
}


接着从缓存中取出这个请求结果。如果不存在在这个请求结果的话,则加入到网络调度线程队列中去。

// Attempt to retrieve this item from cache.
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}


如果存在这条缓存结果时,继续往下走,然后判断是否过期了。如果过期了则同样加入到网络线程队列中去。

// If it is completely expired, just send it to the network.
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}


接下来讲缓存的结果解析成response,

Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));


接着判断是否需要刷新,不需要的话则直接返回缓存结果,否则加入到网络缓存队列中去。

if (!entry.refreshNeeded()) {
//不需要刷新,直接返回结果
mDelivery.postResponse(request, response);
} else {

request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;

if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
//添加到网络队列中去
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
});
} else {

mDelivery.postResponse(request, response);
}
}


这里面有个静态内部类WaitingRequestManager,我们来看下表示什么内容。

WaitingRequestManager

里面有个成员变量,说明表示存储重复请求的。

private final Map<String, List<Request<?>>> mWaitingRequests = new HashMap<>();


接着我们看上面用的方法maybeAddToWaitingRequests,字面意思就是可能需要保存到等待请求队列中去。

if (mWaitingRequests.containsKey(cacheKey)) {
// There is already a request in flight. Queue up.
List<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
if (stagedRequests == null) {
stagedRequests = new ArrayList<Request<?>>();
}
request.addMarker("waiting-for-response");
stagedRequests.add(request);
mWaitingRequests.put(cacheKey, stagedRequests);
if (VolleyLog.DEBUG) {
VolleyLog.d("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
}
return true;
}  else {
// Insert 'null' queue for this cacheKey, indicating there is now a request in
// flight.
mWaitingRequests.put(cacheKey, null);
request.setNetworkRequestCompleteListener(this);
if (VolleyLog.DEBUG) {
VolleyLog.d("new request, sending to network %s", cacheKey);
}
return false;
}


首先判断这个集合中是否存在当前请求,如果存在的话则表示重复请求,则需要排队等待。

以上便是整个缓存请求的处理流程。借用网上的一张图来总结一下,图片原地址为Volley 源码解析

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: