編輯:關於Android編程
Volley最主要的功能其實就是跟網絡打交道,然後從網絡中獲取相對應的數據,雖然有緩存線程(CacheDispatcher),但是如果緩存中沒有對應的記錄的話,還是會將其扔到網絡隊列中,由網絡線程(NetworkDispatcher)來干活。
那麼就看看NetworkDispatcher都干什麼吧,如下:
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Request> request;
while (true) {
try {
// 從隊列中獲取一個請求,如果沒有請求,則會一直阻塞
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 (request.isCanceled()) {
request.finish("network-discard-cancelled");
continue;
}
addTrafficStatsTag(request);
// 調用mNetwork去跟網絡打交道
NetworkResponse networkResponse = mNetwork.performRequest(request);
request.addMarker("network-http-complete");
// 如果服務器返回一個未修改(304)的響應,並且這個請求已經發送過響應對象,不需要再繼續,因為沒改過
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
}
// 分析響應的數據,返回Response對象
Response> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
// 根據request的shouldCache字段來判斷是不是需要緩存,如果需要,則將其放到mCache中。
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
// 調用 mDelivery將Response對象傳回主線程進行UI的更新。
request.markDelivered();
mDelivery.postResponse(request, response);
} catch (VolleyError volleyError) {
parseAndDeliverNetworkError(request, volleyError);//有錯誤,也會調用到mDelivery,將錯誤信息傳回到主線程,進行提示
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
mDelivery.postError(request, new VolleyError(e));
}
}
}網絡線程(NetworkDispatcher)主要做了幾件事情:
1)調用 mQueue的take()方法從隊列中獲取請求,如果沒有請求,則一直阻塞在那裡等待,直到隊列中有新的請求到來。
2)判斷請求有沒有被取消,如果被取消,則重新獲取請求。
3)調用Network對象將請求發送到網絡中,並返回一個 NetworkResponse對象。
4)調用請求的pareseNetworkResonse方法,將NetworkResponse對象解析成相對應的Response對象。
5)判斷請求是否需要緩存,如果需要緩存,則將其Response中cacheEntry對象放到緩存mCache中。
6)調用 mDelivery將Response對象傳到主線程中進行UI更新。
另外有一個要注意的就是,在Volley中,默認是有4個網絡線程同時在跑的,而對應的緩存線程,則只有一個。
從上面的代碼中,可以看到,網絡線程其實是調用 Network對象去實現跟網絡進行溝通的,而在Volley中,默認的Network實現類,則是BasicNetwork類。
下面我們就看看它的performRequest方法:
public NetworkResponse performRequest(Request> request) throws VolleyError {
...
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
Map responseHeaders = new HashMap();
try {
// 添加頭部信息
Map headers = new HashMap();
addCacheHeaders(headers, request.getCacheEntry());
httpResponse = mHttpStack.performRequest(request, headers);//調用HttpStack對象去網絡中獲取數據
StatusLine statusLine = httpResponse.getStatusLine();
int statusCode = statusLine.getStatusCode();
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
// 從響應的狀態行獲取狀態編碼,如果是304(未修改),說明之前已經取過數據了,那麼就直接利用緩存中的數據,構造一個NetworkResonse對象
if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
request.getCacheEntry() == null ? null : request.getCacheEntry().data,
responseHeaders, true);
}
// 有些響應是不帶內容的,比如響應狀態編碼是204的話,添加一個空的byte作為內容,後面好統一處理。
if (httpResponse.getEntity() != null) {
responseContents = entityToBytes(httpResponse.getEntity());
} else {
// Add 0 byte response as a way of honestly representing a
// no-content request.
responseContents = new byte[0];
}
...//忽略了一些log的處理。
return new NetworkResponse(statusCode, responseContents, responseHeaders, false);
} ...//這裡忽略了一些異常處理
} catch (IOException e) {
...
if (responseContents != null) {
networkResponse = new NetworkResponse(statusCode, responseContents,
responseHeaders, false);
if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
statusCode == HttpStatus.SC_FORBIDDEN) {
attemptRetryOnException("auth",
request, new AuthFailureError(networkResponse));//這裡會根據Volley的Retyr機制進行重新獲取。
} else {
throw new ServerError(networkResponse);
}
} else {
throw new NetworkError(networkResponse);
}
}
}
} 1)對於已經有緩存的請求,添加其頭部信息,如下:
private void addCacheHeaders(Mapheaders, Cache.Entry entry) { // If there's no cache entry, we're done. if (entry == null) { return; } if (entry.etag != null) { headers.put("If-None-Match", entry.etag); } if (entry.serverDate > 0) { Date refTime = new Date(entry.serverDate); headers.put("If-Modified-Since", DateUtils.formatDate(refTime)); } }
3)根據狀態編碼來返回不同的Response對象,如304(未修改)就返回緩存中的數據,如果不是,則根據響應中的數據,重新構造一個NetworkResponse對象。
4)BasicNetwork實現了重試的機制,如果第一次從網絡獲取失敗,默認會重新再嘗試一次,如果失敗,則會將Error返回,默認的實現類是DefaultRetryPolicy類。
在Network中返回的NetworkResponse對象,會在NetworkDispatcher中由具體的Request(比如ImageRequest,JsonRequest)類來進行解析,再最後返回給UI線程。
結束!
關於緩存線程的介紹:
Android中關於Volley的使用(六)認識 CacheDispatcher
android顯示機制
前言本文是通過閱讀各種文章及代碼,總結出來的,其中難免有些地方理解得不對,歡迎大家批評指正。顯示系統基礎知識定義在一個典型的顯示系統中,一般包括CPU、GPU、displ
Android項目之_硅谷商城項目全套源碼解析(五、發現)
一、簡介上篇博客概括的介紹了硅谷商城項目的分類模塊技術要點。本篇內容給大家講解硅谷商城項目發現模塊,發現模塊用的技術包括:采用TabLayout實現標題的切換、采用Ope
Android懸浮對話框(即點即關對話框)實現代碼
Activity是Android系統的4個應用程序組件之一。通過傳統方法顯示的Activity都是充滿整個屏幕,也就是全屏的Activity。事實上,Activity不僅
Android控件系列之Button以及Android監聽器使用介紹
學習目的: 1、掌握在Android中如何建立Button 2、掌握Button的常用屬性 3、掌握Button按鈕的點擊事件(監聽器) Button是各種UI中最常用的