Volley源码解析<五> CacheDispatcher和NetworkDispatcher
@[Volley, 调度器, CacheDispatcher, NetworkDispatcher]
声明:转载请注明出处,知识有限,如有错误,请多多交流指正!
结构
主要通过RequestQueue调用start()方法启动CacheDispatcher和NetworkDispatcher线程
CacheDispatcher
1. 构造方法
CacheDispatcher继承自Thread,当被start后就执行它的run方法,在RequestQueue.add方法中,如果使用缓存直接就将Request放入缓存队列mCacheQueue中了,使用mCacheQueue的位置就是CacheDispatcher,CacheDispatcher的构造函数中传入了缓存队列mCacheQueue、网络队列mNetworkQueue、缓存对象mCache及结果派发器mDelivery
public CacheDispatcher(BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue, Cache cache, ResponseDelivery delivery) {
mCacheQueue = cacheQueue;
mNetworkQueue = networkQueue;
mCache = cache;
mDelivery = delivery;
}
其中
cacheQueue:缓存请求队列,就是RequestQueue中的mCacheQueue
networkQueue:网络请求队列,就是RequestQueue中的mNetworkQueue
cache:保存缓存数据,就是RequestQueue中的mCache
delivery:用于分发响应结果,就是RequestQueue中的mDelivery
2. 主要运行方法run()
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// Make a blocking call to initialize the cache.
// 初始化缓存
mCache.initialize();
Request<?> request;
while (true) {
// release previous request object to avoid leaking request object when mQueue is drained.
request = null;
try {
// Take a request from the queue.
// 从缓存队列中取出请求
request = mCacheQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
try {
request.addMarker("cache-queue-take");
// If the request has been canceled, don't bother dispatching it.
// 取消请求
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
// Attempt to retrieve this item from cache.
Cache.Entry entry = mCache.get(request.getCacheKey());
//缓存已过期(包括expired与Soft-expired)
// 无缓存数据,则加入网络请求
if (entry == null) {
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
mNetworkQueue.put(request);
continue;
}
// If it is completely expired, just send it to the network.
// 判断缓存的新鲜度,过期了,加入网络请求
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
// We have a cache hit; parse its data for delivery back to the request.
request.addMarker("cache-hit");
//从缓存中取出请求响应并进行解析
Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
//判断缓存是需要刷新
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
// 缓存没有Soft-expired,则直接通过mDelivery将解析好的结果交付给请求发起者
mDelivery.postResponse(request, response);
} else {
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
final Request<?> finalRequest = request;
//需要刷新,那么就再次提交网络请求...获取服务器的响应...
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
// 网络来更新请求响应
mNetworkQueue.put(finalRequest);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
}
}
}
3. 其他
//用于判断线程是否结束,用于退出线程
private volatile boolean mQuit = false;
//出线程
public void quit() {
mQuit = true;
interrupt();
}
在run方法中一直运行着while (true)
,那么是如何停止线程的呢?当通过调用quit
方法中interrupt()
时,会InterruptedException
异常退出线程
NetworkDispatcher
1. 构造方法
原理和CacheDispatcher
基本上一样的,主要用于网络请求
public NetworkDispatcher(BlockingQueue<Request<?>> queue, Network network, Cache cache, ResponseDelivery delivery) {
mQueue = queue;
mNetwork = network;
mCache = cache;
mDelivery = delivery;
}
其中
queue:网络请求队列,就是RequestQueue中的mNetworkQueue
network:网络请求封装类,就是BasicNetwork
cache:保存缓存数据,就是RequestQueue中的mCache
delivery:用于分发响应结果,就是RequestQueue中的mDelivery
2. 主要运行方法run()
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Request<?> request;
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
// release previous request object to avoid leaking request object when mQueue is drained.
request = null;
try {
// Take a request from the queue.
request = mQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
try {
request.addMarker("network-queue-take");
// If the request was cancelled already, do not perform the
// network request.
// 如果请求被中途取消
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
continue;
}
// 流量统计用的
addTrafficStatsTag(request);
// Perform the network request.
// 请求数据
NetworkResponse networkResponse = mNetwork.performRequest(request);
request.addMarker("network-http-complete");
// If the server returned 304 AND we delivered a response already,
// we're done -- don't deliver a second identical response.
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
//如果是相同的请求,那么服务器就返回一次响应
request.finish("not-modified");
continue;
}
// Parse the response here on the worker thread.
// 解析响应数据
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
// Write to cache if applicable.
// TODO: Only update cache metadata instead of entire record for 304s.
if (request.shouldCache() && response.cacheEntry != null) {
// 缓存数据
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
// Post the response back.
//确认请求要被分发
request.markDelivered();
//发送请求
mDelivery.postResponse(request, response);
} catch (VolleyError volleyError) {
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
VolleyError volleyError = new VolleyError(e);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
mDelivery.postError(request, volleyError);
}
}
}