編輯:關於Android編程
當調用 RequestQueue的 add()方法添加 Request 的時候,會根據請求的一個參數 shouldCache,來判斷要不要去緩存中查詢,如果是去緩存中查詢,那麼就會把請求放到CacheQueue中,如下:
mWaitingRequests.put(cacheKey, null);
mCacheQueue.add(request);
這個時候,線程CacheDispatcher其實已經在跑了,到它的run方法中來看一下:
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// 初始化緩存
mCache.initialize();
while (true) {
try {
// 從緩存隊列中獲取一個請求
final Request> request = mCacheQueue.take();
request.addMarker("cache-queue-take");
// 如果請求已經被取消,則重新獲取請求
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
// 根據request的cacheKey從緩存中得到對應的記錄
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// 這裡說明緩存中沒有對應的記錄,那麼需要去網絡中獲取,那麼就將它放到Network的隊列中
mNetworkQueue.put(request);
continue;
}
// 如果緩存中有記錄,但是已經過期了或者失效了,也需要去網絡獲取,放到Network隊列中
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
// 如果上面的情況都不存在,說明緩存中存在這樣記錄,那麼就調用request的parseNetworkResponse方法,獲取一個響應Response
request.addMarker("cache-hit");
Response> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
if (!entry.refreshNeeded()) {
// 緩存記錄,不需要更新,那麼就直接調用mDelivery,傳回給主線程去更新。
mDelivery.postResponse(request, response);
} else {
// 還存在這樣一種情況,緩存記錄存在,但是它約定的生存時間已經到了(還未完全過期,叫軟過期),可以將其發送到主線程去更新
// 但同時,也要從網絡中更新它的數據
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
// 將其傳回主線程的同時,將請求放到Network隊列中。
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
}
}1)初始化本地緩存
2)開始一個無限的循環,調用 mCacheQueue的take方法,來獲得一個請求,而mCacheQueue是一個BlockingQueue,也就是說,當隊列中沒有請求的時候,take方法就會一直阻塞在這裡,等待隊列中的請求,而一旦隊列中有新的請求進來了,那麼它就會馬上執行下去。
/** The queue of requests coming in for triage. */
private final BlockingQueue> mCacheQueue;
/** The queue of requests going out to the network. */
private final BlockingQueue> mNetworkQueue; 4)根據請求的CacheKey去緩存中尋找相對應的記錄,如果找不到對應的記錄,或者對應的記錄過期了,則將其放到NetworkQueue隊列中。
5)緩存中存在相對應的記錄,那麼調用每個請求具體的實現方法 parseNetworkResponse函數,根據具體的請求去解析得到對應的響應Response對象。
6)獲得Response對象之後,還會再進行判斷這個請求是不是進行一次網絡的更新,這是根據記錄的soft-ttl (time-to-live)屬性,如下:
/** True if the entry is expired. */
public boolean isExpired() {
return this.ttl < System.currentTimeMillis();
}
/** True if a refresh is needed from the original data source. */
public boolean refreshNeeded() {
return this.softTtl < System.currentTimeMillis();
}
從這裡也可以看到,expired的判斷跟refreshNeed的判斷是兩個字段,一個是ttl,一個是softTtl。
如果需要進行更新,那麼就會在發送響應結果回主線程更新的同時,再將請求放到NetworkQueue中,從網絡中更新請求對應的數據。如果不需要,則直接將結果調用mDelivery傳回主線程進行UI的更新。
CacheDispatcher做的事情並不多,因為Volley主要的功能其實還是跟網絡打交道,所以主要的實現,其實還是NetworkDispatcher。
結束!
【我的Android進階之旅】 高效的設計稿標注及測量工具Markman介紹
前言 高效的設計稿標注及測量工具Markman介紹。最近有個煩惱是UI設計師可能太忙了,經常給出的UI設計稿中有很多地方都沒有標注,比如長度和顏色值等。這個時候每次都要通
Android開發自定義View實現數字與圖片無縫切換的2048
最近在學自定義View,無意中看到鴻洋大神以前寫過的2048,看起來很不錯,所以自己在他的基礎上做一個加強版的2048。先看圖: 功能除了正常的2048外,還支
跨平台移動WEB應用開發框架iMAG入門教程
iMAG是一個非常簡潔高效的移動跨平台開發框架,開發一次可以同時兼容Android和iOS平台,有點兒Web開發基礎就能很快上手。當前移動端跨平台開發的框架有很多,但用i
Android 4.4(KitKat)中apk包的安裝過程
其實對於apk包的安裝,4.4和之前版本沒大的差別。Android中app安裝主要有以下幾種情況:系統啟動時安裝,adb命令安裝,Google