文章摘要
1、volley 緩存線程運行流程
2、volley 實現(xiàn)分解步驟
附:獲取Volley源代碼
Demos案例源碼:https://github.com/HailouWang/DemosForApi、
簡介:
volley有兩個主要的民工,CacheDispatcher以及NetworkDispatcher,也是兩個線程,管理并處理Request任務。
volley為了保證大批量的網絡請求以及數(shù)據(jù)解析不會影響到主線程的用戶交互,使用了很多線程以及線程封裝技巧。包括這里的Cache。
在用戶發(fā)起網絡請求后,volley就將用戶的請求,丟到了本文介紹的緩存進程,緩存線程如果沒有能力處理,就丟給網絡線程,并告訴它,老大需要數(shù)據(jù)結果,你趕緊去網絡上去拿。老大只要結果,不要過程。
主線程很忙,ResponseDelivery負責傳遞消息,伴君如伴虎,為了防止打擾到主線程的工作,ResponseDelivery也可以有一個線程,在目前的源碼里,ResponseDelivery充分利用Handler的MessageQueue優(yōu)勢,管理并小心的將結果傳遞給主線程。
那么,本文就來介紹下緩存線程的工作原理:
一、CacheDispatcher線程
1、Volley中有三個線程,CacheDispatcher是其中的緩存線程。
2、CacheDispatcher緩沖線程的目的是在緩沖池中,執(zhí)行分流,將Request請求分發(fā)出去。
線程循環(huán)運行,線程原料來自mCacheQueue,在主線程可通過RequestQueue.add方法將請求加入mCacheQueue。-
3、可以將工作流程簡單歸納為以下幾步:
- 1、線程循環(huán)運行,線程原料來自mCacheQueue。
- 2、優(yōu)先從緩沖區(qū)獲得數(shù)據(jù),如果緩存區(qū)中存在數(shù)據(jù),則直接返回數(shù)據(jù)給主線程。
- 3、如果緩存區(qū)【沒有命中數(shù)據(jù)】或者【緩存數(shù)據(jù)過期】,則將請求(Request)分發(fā)給NetworkDispatcher(網絡線程),網絡線程會重新同步數(shù)據(jù)。
附:流程圖
- Volley Cache Thread流程圖.png
二、實現(xiàn)分析
1、線程循環(huán)運行,獲得Request對象
while (true) {
try {
// Get a request from the cache triage queue, blocking until
// at least one is available.
//1、hlwang:CacheDispatcher原料來自mCacheQueue,第一步,獲得Request
final Request<?> request = mCacheQueue.take();
request.addMarker("cache-queue-take");
... ...
}
}
2、如果Request被用戶取消了,則不再需要繼續(xù)執(zhí)行了
// If the request has been canceled, don't bother dispatching it.
//2、hlwang:如果request已取消,已經不需要繼續(xù)了
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
3、優(yōu)先檢查緩存區(qū),如果數(shù)據(jù)沒有命中(即:數(shù)據(jù)不存在),則交給Network線程去同步數(shù)據(jù)
// Attempt to retrieve this item from cache.
//3、hlwang:如果在緩存中,不存在數(shù)據(jù),說明是新數(shù)據(jù),則:交給mNetworkQueue去同步新數(shù)據(jù)。
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
mNetworkQueue.put(request);
continue;
}
4、如果緩存數(shù)據(jù)過期了,依舊交給Network線程去同步數(shù)據(jù)
// If it is completely expired, just send it to the network.
//4、hlwang:如果緩存過期,那么說明數(shù)據(jù)太舊了,交給mNetworkQueue去同步新數(shù)據(jù)。
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
5、緩存的數(shù)據(jù)被命中,則解析緩存數(shù)據(jù),構建Response對象
// We have a cache hit; parse its data for delivery back to the request.
//5、wanghailu:我們命中了一條緩存數(shù)據(jù)(w找到了一個保質期內的緩存hl),解析數(shù)據(jù)并構建響應對象Response。
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
6、如果緩存數(shù)據(jù),不需要刷新,則將響應數(shù)據(jù),通過Delivery回調給用戶
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
//6、如果entry數(shù)據(jù)不需要刷新,則使用mDelivery將響應傳遞出去
mDelivery.postResponse(request, response);
}
7、緩存的數(shù)據(jù)需要再次更新,那么現(xiàn)將緩存數(shù)據(jù)返回給用戶,接著通過主線程發(fā)起同步數(shù)據(jù)請求
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
//7、雖然被緩存命中,但數(shù)據(jù)輕微過期。我們可以將緩存響應數(shù)據(jù)傳遞分發(fā),
//但我們同樣需要將請求發(fā)送到mNetworkQueue去刷新、更新。
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
//7.1、更新response狀態(tài)為 媒介
response.intermediate = true;
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
//7.2、主線程分發(fā)
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}