Volley源碼解析<五> CacheDispatcher和NetworkDispatcher
@[Volley, 排程器, CacheDispatcher, NetworkDispatcher]
聲明:轉載請注明出處,知識有限,如有錯誤,請多多交流指正!
- Volley源碼解析五 CacheDispatcher和NetworkDispatcher
-
- 結構
- 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);
}
}
}