前面三篇文章從最基礎的TCP,HTTP協議理論開始,而後介紹了在Android的開發中所使用的HttpClient和HttpUrlConnection這兩種Http客戶端。在本文中,咱們一塊兒來學習一下在Android開發中常用的volley框架。首先,咱們會從架構的角度瞭解一下整個框架的結構,而後從源碼的角度理解框架實現細節。緩存
volley是Google在13年發佈的一款Android異步網絡請求框架。volley有着鮮明的特色:適用於小數據量且頻繁的網絡請求。這個特色特別適合於Android應用程序的網絡操做。另外,咱們從接下來將要介紹的架構中能夠發現,volley採用了大量面向接口的設計,保證了整個框架的開放性和靈活性,能夠根據不一樣的狀況需求進行定製。同時,volley也提供了簡單的圖片加載工具。服務器
在咱們研究volley框架的結構以前,咱們不妨本身先來思考一下如何實現一款網絡操做的框架。首先,咱們根據實際需求設計網絡操做請求(無非就是URL及其參數),而後使用多線程併發來執行和處理網絡操做請求任務。從服務器中取到數據後,將數據放在內存的cache中以便應用程序使用。網絡
其實volley框架也是如此設計的,以下圖所示:多線程
從圖中咱們能夠看到,整個框架的結構分爲4個部分:架構
一、volley使用一個請求隊列來管理各類網絡請求Request。Request自己是一個描述請求的抽象類,咱們能夠根據具體需求狀況實現該抽象類。volley也提供了一些Request子類,例如StringRequest,JsonRequest,ImageRequest等等。併發
二、在請求隊列RequestQueue中,有兩種個輪詢分發線程負責對請求任務進行分發調度。第一種是CacheDispatcher,負責調度數據保存在cache中的請求任務;第二種是NetworkDispatcher,負責調度數據在遠端服務器上的請求任務。另外,RequestQueue中還有一個叫做ResponseDelivery的接口,用於進行結果分發。請求隊列中的網絡請求會首先被放入Cache任務隊列中,被CacheDispatcher線程調度。CacheDispatcher會試圖從cache中取出該任務所請求的數據,若是命中則交給ResponseDelivery解析該數據並返回給應用程序;若是未命中,或者緩存失效等狀況下,則將該請求任務加入到網絡任務的隊列中,供NetworkDispatcher進程調度。NetworkDispatcher請求結束則將結果交給ResponseDelivery做後續的處理。框架
三、從上面的分析中咱們能夠看出,咱們所請求的數據主要存在兩個個地方:Cache和網絡。volley中分別使用Cache和HttpStack這兩個接口來描述它們以及所需執行的操做。其中,HttpStack負責處理http網絡請求,volley中有兩種方式實現了HttpStack接口:基於 HttpURLConnection 的HurlStack 和 基於HttpClient 的HttpClientStack 。而Cache既但是基於SD卡,又能夠基於內存。異步
四、經過上面所述的兩個接口能夠獲取並操做咱們請求的數據,這些數據主要分佈在網絡服務器和本地內存或SD卡中。工具
volley維護了一個請求隊列來管理應用程序的網絡請求,並採用了單例模式來保證一個應用程序只含有一個請求隊列。一般狀況下,咱們會繼承Application類,並經過newRequestQueue方法來建立一個請求隊列。從源碼中咱們能夠看出,在Android2.3以上使用了基於HttpUrlConnection的HurlStack處理網絡請求,而2.3如下使用了基於httpclient的HttpClientStack來處理網絡請求。這裏的緣由在上一篇文章中咱們提到過,這裏再也不贅述。下面咱們順着請求的提交—>處理—>完成 的這條線路來研究一下框架的內部細節。post
針對不一樣的網絡請求,咱們能夠實現Request這個抽象類。該抽象類描述了請求的url,方式,head,body以及優先級等等信息。然而volley已經爲咱們實現了大部分的子類來知足各類需求。在Request的子類中,咱們須要重寫兩個方法:
protected Response<T> parseNetworkResponse(NetworkResponse response) :用於將網絡返回的字節流解析爲合適的數據類型。 protected void deliverResponse(T response) :將解析好的數據傳遞給它的監聽回調。
另外,若是咱們自定義Request,一般也會重寫getBody()方法來構建body內容;若是並未重寫getBody方法,那麼將會把getParams()方法返回的K-V值拼接起來的字節碼做爲body。
定義好了請求Request,接下來咱們來經過源碼來研究一下RequestQueue這個類。RequestQueue做爲volley框架的核心類,負責管理應用程序的網絡請求。咱們在使用volley進行網絡的時候,向請求隊列提交了Request後發生了什麼呢?請看下圖。
RequestQueue使用一個set來存儲一個未處理的請求。當咱們提交一個請求後,RequestQueue會將該請求加入到這個集合中:
private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
咱們在上面已經提到過,咱們主要從cache和網絡來請求數據。因而,在RequestQueue中維護了兩個請求隊列:cache請求隊列CacheQueue和網絡請求隊列NetworkQueue:
private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<Request<?>>(); private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<Request<?>>();
咱們能夠看到,這兩個隊列採用了優先阻塞隊列PriorityBlockingQueue來維護請求。每一個新請求都會先放入cache隊列等待調度,只有在cache未命中或無效的狀況下會被放入網絡請求隊列。可是,若是一個請求在處理的同時,又有相同url的請求怎麼辦呢?顯然重複的請求只要到cache中去取就行了,無需再次進行網絡請求,因此volley採用一個map來管理重複的請求,將它們暫時放入map中等待:
private final Map<String, Queue<Request<?>>> mWaitingRequests = new HashMap<String, Queue<Request<?>>>();
提交了請求以後,接下來的工做就是對請求進行處理了,接下來咱們來研究一下volley的調度策略。
對應於兩種請求隊列,分別使用CacheDispatcher和NetworkDispatcher兩個線程來調度分發,上面已經介紹過這兩種線程了,來看一下RequestQueue初始化和啓動的代碼:
public void start() { stop(); // Make sure any currently running dispatchers are stopped. // Create the cache dispatcher and start it. mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); // Create network dispatchers (and corresponding threads) up to the pool size. for (int i = 0; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } }
從源碼中咱們能夠看出RequestQueue啓動了一個CacheDispatcher線程和多個NetworkDispatcher線程來完成調度分發,下面咱們來研究一下這兩種線程。
CacheDispatcher啓動後會不斷地輪詢mCacheQueue,隊列爲空時則等待;若是請求的cache未命中,過時或者無效,則會把該請求加入到mNetworkQueue中。當請求處理完成後則會將結果交給ResponseDelivery作最後的處理。具體流程以下:
NetworkDispatcher不斷輪詢mNetworkQueue取出請求去執行,隊列爲空則等待,請求處理結束則將結果傳遞給 ResponseDelivery 去執行後續處理,並判斷結果是否要進行緩存。具體流程以下:
從圖中能夠看到,不管是CacheDispatcher仍是NetworkDispatcher,請求結束後都會將結果交給ResponseDelivery這個接口來作後續處理,在ResponseDelivery中主要有三個方法還傳遞請求結果或者錯誤:
public void postResponse(Request<?> request, Response<?> response) // 用於傳遞請求結果, request 和 response 參數分別表示請求信息和返回結果信息。 public void postResponse(Request<?> request, Response<?> response, Runnable runnable) //用於傳遞請求結果,並在完成傳遞後執行 Runnable public void postError(Request<?> request, VolleyError error); //用於傳輸請求錯誤
當一個請求處理完成後,首先須要將當前處理集合mCurrentRequests 中的請求移除,而後在重複請求的mWaitingRequests中查詢是否有正在等待的重複請求,若是有則放入緩存隊列中處理。
經過從請求的建立—>提交—>處理—>完成 這條主線,本文簡單的介紹了volley框架的執行流程以及部分細節。volley的整個框架採用了大量的面向接口的設計,保證了使用的靈活性和框架的開放性。同時,volley又實現了不少接口來幫助開發者應對各類需求,在保證靈活性的同時也減小了不少繁瑣的工做。