文章摘要
1柑爸、volley 緩存線程運行流程
2、volley 實現(xiàn)分解步驟
附:獲取Volley源代碼
Demos案例源碼:https://github.com/HailouWang/DemosForApi远剩、
簡介:
volley有兩個主要的民工,CacheDispatcher以及NetworkDispatcher骇窍,也是兩個線程瓜晤,管理并處理Request任務(wù)。
volley為了保證大批量的網(wǎng)絡(luò)請求以及數(shù)據(jù)解析不會影響到主線程的用戶交互腹纳,使用了很多線程以及線程封裝技巧痢掠。包括這里的Cache。
在用戶發(fā)起網(wǎng)絡(luò)請求后嘲恍,volley就將用戶的請求足画,丟到了本文介紹的緩存進程,緩存線程如果沒有能力處理佃牛,就丟給網(wǎng)絡(luò)線程锌云,并告訴它,老大需要數(shù)據(jù)結(jié)果吁脱,你趕緊去網(wǎng)絡(luò)上去拿桑涎。老大只要結(jié)果,不要過程兼贡。
主線程很忙攻冷,ResponseDelivery負責(zé)傳遞消息,伴君如伴虎遍希,為了防止打擾到主線程的工作等曼,ResponseDelivery也可以有一個線程,在目前的源碼里凿蒜,ResponseDelivery充分利用Handler的MessageQueue優(yōu)勢禁谦,管理并小心的將結(jié)果傳遞給主線程。
那么废封,本文就來介紹下緩存線程的工作原理:
一州泊、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(網(wǎng)絡(luò)線程)疏叨,網(wǎng)絡(luò)線程會重新同步數(shù)據(jù)。
附:流程圖
二穿剖、實現(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已取消蘸劈,已經(jīng)不需要繼續(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ù),構(gòu)建Response對象
// We have a cache hit; parse its data for delivery back to the request.
//5僻族、wanghailu:我們命中了一條緩存數(shù)據(jù)(w找到了一個保質(zhì)期內(nèi)的緩存hl)粘驰,解析數(shù)據(jù)并構(gòu)建響應(yīng)對象Response屡谐。
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
6、如果緩存數(shù)據(jù)蝌数,不需要刷新愕掏,則將響應(yīng)數(shù)據(jù),通過Delivery回調(diào)給用戶
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
//6顶伞、如果entry數(shù)據(jù)不需要刷新饵撑,則使用mDelivery將響應(yīng)傳遞出去
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ù)輕微過期语卤。我們可以將緩存響應(yīng)數(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.
}
}