Android之Volley 源码解析
原文來自:http://www.codekk.com?
1. 功能介紹?
1.1. Volley
Volley 是 Google 推出的 Android 異步網絡請求框架和圖片加載框架。在 Google I/O 2013 大會上發布。
名字由來:a burst or emission of many things or a large amount at once?
發布演講時候的配圖?
從名字由來和配圖中無數急促的火箭可以看出 Volley 的特點:特別適合數據量小,通信頻繁的網絡操作。(個人認為 Android 應用中絕大多數的網絡操作都屬于這種類型)。
1.2 Volley 的主要特點
(1). 擴展性強。Volley 中大多是基于接口的設計,可配置性強。?
(2). 一定程度符合 Http 規范,包括返回 ResponseCode(2xx、3xx、4xx、5xx)的處理,請求頭的處理,緩存機制的支持等。并支持重試及優先級定義。?
(3). 默認 Android2.3 及以上基于 HttpURLConnection,2.3 以下基于 HttpClient 實現,這兩者的區別及優劣在4.2.1 Volley中具體介紹。?
(4). 提供簡便的圖片加載工具。
2.1. 總體設計圖?
2.2. Volley 中的概念
簡單介紹一些概念,在詳細設計中會仔細介紹。?
Volley 的調用比較簡單,通過 newRequestQueue(…) 函數新建并啟動一個請求隊列RequestQueue后,只需要往這個RequestQueue不斷 add Request 即可。
Volley:Volley 對外暴露的 API,通過 newRequestQueue(…) 函數新建并啟動一個請求隊列RequestQueue。
Request:表示一個請求的抽象類。StringRequest、JsonRequest、ImageRequest 都是它的子類,表示某種類型的請求。
RequestQueue:表示請求隊列,里面包含一個CacheDispatcher(用于處理走緩存請求的調度線程)、NetworkDispatcher數組(用于處理走網絡請求的調度線程),一個ResponseDelivery(返回結果分發接口),通過 start() 函數啟動時會啟動CacheDispatcher和NetworkDispatchers。
CacheDispatcher:一個線程,用于調度處理走緩存的請求。啟動后會不斷從緩存請求隊列中取請求處理,隊列為空則等待,請求處理結束則將結果傳遞給ResponseDelivery去執行后續處理。當結果未緩存過、緩存失效或緩存需要刷新的情況下,該請求都需要重新進入NetworkDispatcher去調度處理。
NetworkDispatcher:一個線程,用于調度處理走網絡的請求。啟動后會不斷從網絡請求隊列中取請求處理,隊列為空則等待,請求處理結束則將結果傳遞給ResponseDelivery去執行后續處理,并判斷結果是否要進行緩存。
ResponseDelivery:返回結果分發接口,目前只有基于ExecutorDelivery的在入參 handler 對應線程內進行分發。
HttpStack:處理 Http 請求,返回請求結果。目前 Volley 中有基于 HttpURLConnection 的HurlStack和 基于 Apache HttpClient 的HttpClientStack。
Network:調用HttpStack處理請求,并將結果轉換為可被ResponseDelivery處理的NetworkResponse。
Cache:緩存請求結果,Volley 默認使用的是基于 sdcard 的DiskBasedCache。NetworkDispatcher得到請求結果后判斷是否需要存儲在 Cache,CacheDispatcher會從 Cache 中取緩存結果。
Volley 請求流程圖?
4.1 類關系圖?
圖中紅色圈內的部分,組成了 Volley 框架的核心,圍繞 RequestQueue 類,將各個功能點以組合的方式結合在了一起。各個功能點也都是以接口或者抽象類的形式提供。?
紅色圈外面的部分,在 Volley 源碼中放在了toolbox包中,作為 Volley 為各個功能點提供的默認的具體實現。?
通過類圖我們看出, Volley 有著非常好的拓展性。通過各個功能點的接口,我們可以給出自定義的,更符合我們需求的具體實現。
多用組合,少用繼承;針對接口編程,不針對具體實現編程。
優秀框架的設計,令人叫絕,受益良多。?
4.2 核心類功能介紹?
4.2.1 Volley.java
這個和 Volley 框架同名的類,其實是個工具類,作用是構建一個可用于添加網絡請求的RequestQueue對象。?
(1). 主要函數?
Volley.java 有兩個重載的靜態方法。
public static RequestQueue newRequestQueue(Context context)
public static RequestQueue newRequestQueue(Context context, HttpStack stack)?
第一個方法的實現調用了第二個方法,傳 HttpStack 參數為 null。?
第二個方法中,如果 HttpStatck 參數為 null,則如果系統在 Gingerbread 及之后(即 API Level >= 9),采用基于 HttpURLConnection 的 HurlStack,如果小于 9,采用基于 HttpClient 的 HttpClientStack。
if (stack == null) {?
if (Build.VERSION.SDK_INT >= 9) {?
stack = new HurlStack();?
} else {?
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));?
}?
}?
得到了 HttpStack,然后通過它構造一個代表網絡(Network)的具體實現BasicNetwork。?
接著構造一個代表緩存(Cache)的基于 Disk 的具體實現DiskBasedCache。?
最后將網絡(Network)對象和緩存(Cache)對象傳入構建一個 RequestQueue,啟動這個 RequestQueue,并返回。
Network network = new BasicNetwork(stack);?
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);?
queue.start();?
return queue;?
我們平時大多采用Volly.newRequestQueue(context)的默認實現,構建RequestQueue。?
通過源碼可以看出,我們可以拋開 Volley 工具類構建自定義的RequestQueue,采用自定義的HttpStatck,采用自定義的Network實現,采用自定義的Cache實現等來構建RequestQueue。?
優秀框架的高可拓展性的魅力來源于此啊?
(2). HttpURLConnection 和 AndroidHttpClient(HttpClient 的封裝)如何選擇及原因:?
在 Froyo(2.2) 之前,HttpURLConnection 有個重大 Bug,調用 close() 函數會影響連接池,導致連接復用失效,所以在 Froyo 之前使用 HttpURLConnection 需要關閉 keepAlive。?
另外在 Gingerbread(2.3) HttpURLConnection 默認開啟了 gzip 壓縮,提高了 HTTPS 的性能,Ice Cream Sandwich(4.0) HttpURLConnection 支持了請求結果緩存。?
再加上 HttpURLConnection 本身 API 相對簡單,所以對 Android 來說,在 2.3 之后建議使用 HttpURLConnection,之前建議使用 AndroidHttpClient。
(3). 關于 User Agent?
通過代碼我們發現如果是使用 AndroidHttpClient,Volley 還會將請求頭中的 User-Agent 字段設置為 App 的?packageName/{versionCode},如果異常則使用 “volley/0”,不過這個獲取 User-Agent 的操作應該放到 if else 內部更合適。而對于 HttpURLConnection 卻沒有任何操作,為什么呢??
如果用 Fiddler 或 Charles 對數據抓包我們會發現,我們會發現 HttpURLConnection 默認是有 User-Agent 的,類似:
Dalvik/1.6.0 (Linux; U; Android 4.1.1; Google Nexus 4 - 4.1.1 - API 16 - 768x1280_1 Build/JRO03S)?
經常用 WebView 的同學會也許會發現似曾相識,是的,WebView 默認的 User-Agent 也是這個。實際在請求發出之前,會檢測 User-Agent 是否為空,如果不為空,則加上系統默認 User-Agent。在 Android 2.1 之后,我們可以通過
String userAgent = System.getProperty(“http.agent”);?
得到系統默認的 User-Agent,Volley 如果希望自定義 User-Agent,可在自定義 Request 中重寫 getHeaders() 函數
@Override?
public Map
總結
以上是生活随笔為你收集整理的Android之Volley 源码解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android之滑动事件冲突解决 Tou
- 下一篇: Android之图形图像之使用Path类