Android異步網絡請求框架-Volley

Android 異步網絡請求框架-Volley

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. 總體設計

2.1 總體設計圖

這里寫圖片描述

上面是 Volley 的總體設計圖,主要是通過兩種Dispatch Thread不斷從RequestQueue中取出請求,根據是否已緩存調用Cache或Network這兩類數據獲取接口之一,從內存緩存或是服務器取得請求的數據,然后交由ResponseDelivery去做結果分發及回調處理。
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 中取緩存結果。

3. 流程圖

Volley 請求流程圖:


這里寫圖片描述

4. 詳細設計

4.1 類關系圖

這里寫圖片描述

這是 Volley 框架的主要類關系圖
圖中紅色圈內的部分,組成了 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。

4.2.2 Request.java

代表一個網絡請求的抽象類。我們通過構建一個Request類的非抽象子類(StringRequest、JsonRequest、ImageRequest 或自定義)對象,并將其加入到?RequestQueue?中來完成一次網絡請求操作。
Volley 支持 8 種 Http 請求方式 GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE, PATCH
Request 類中包含了請求 url,請求請求方式,請求 Header,請求 Body,請求的優先級等信息。
因為是抽象類,子類必須重寫的兩個方法。
abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
子類重寫此方法,將網絡返回的原生字節內容,轉換成合適的類型。此方法會在工作線程中被調用。
abstract protected void deliverResponse(T response);
子類重寫此方法,將解析成合適類型的內容傳遞給它們的監聽回調。
以下兩個方法也經常會被重寫

public byte[] getBody()

重寫此方法,可以構建用于 POST、PUT、PATCH 請求方式的 Body 內容。
protected Map<String, String> getParams()
在上面getBody函數沒有被重寫情況下,此方法的返回值會被 key、value 分別編碼后拼裝起來轉換為字節碼作為 Body 內容。

4.2.3 RequestQueue.java

Volley 框架的核心類,將請求 Request 加入到一個運行的RequestQueue中,來完成請求操作。
(1). 主要成員變量
RequestQueue 中維護了兩個基于優先級的 Request 隊列,緩存請求隊列和網絡請求隊列。
放在緩存請求隊列中的 Request,將通過緩存獲取數據;放在網絡請求隊列中的 Request,將通過網絡獲取數據。

private final PriorityBlockingQueue<Request<?>> mCacheQueue = new PriorityBlockingQueue<Request<?>>();
private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<Request<?>>();

維護了一個正在進行中,尚未完成的請求集合。

private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();

維護了一個等待請求的集合,如果一個請求正在被處理并且可以被緩存,后續的相同 url 的請求,將進入此等待隊列。

private final Map<String, Queue<Request<?>>> mWaitingRequests = new HashMap<String, Queue<Request<?>>>();

(2). 啟動隊列
創建出 RequestQueue 以后,調用 start 方法,啟動隊列。

/**
 * Starts the dispatchers in this queue.
 */
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();
    }
}

start 方法中,開啟一個緩存調度線程CacheDispatcher和 n 個網絡調度線程NetworkDispatcher,這里 n 默認為 4,存在優化的余地,比如可以根據 CPU 核數以及網絡類型計算更合適的并發數。
緩存調度線程不斷的從緩存請求隊列中取出 Request 去處理,網絡調度線程不斷的從網絡請求隊列中取出 Request 去處理。
(3). 加入請求

public <T> Request<T> add(Request<T> request);
這里寫圖片描述

流程圖如下:


這里寫圖片描述

(4). 請求完成

void finish(Request<?> request)

Request 請求結束:


這里寫圖片描述

(1). 首先從正在進行中請求集合mCurrentRequests中移除該請求。
(2). 然后查找請求等待集合mWaitingRequests中是否存在等待的請求,如果存在,則將等待隊列移除,并將等待隊列所有的請求添加到緩存請求隊列中,讓緩存請求處理線程CacheDispatcher自動處理。
(5). 請求取消

public void cancelAll(RequestFilter filter)
public void cancelAll(final Object tag)

取消當前請求集合中所有符合條件的請求。
filter 參數表示可以按照自定義的過濾器過濾需要取消的請求。
tag 表示按照Request.setTag設置好的 tag 取消請求,比如同屬于某個 Activity 的。

4.2.4 CacheDispatcher.java

一個線程,用于調度處理走緩存的請求。啟動后會不斷從緩存請求隊列中取請求處理,隊列為空則等待,請求處理結束則將結果傳遞給ResponseDelivery 去執行后續處理。當結果未緩存過、緩存失效或緩存需要刷新的情況下,該請求都需要重新進入NetworkDispatcher去調度處理。
(1). 成員變量

BlockingQueue<Request<?>> mCacheQueue 緩存請求隊列
BlockingQueue<Request<?>> mNetworkQueue 網絡請求隊列
Cache mCache 緩存類,代表了一個可以獲取請求結果,存儲請求結果的緩存
ResponseDelivery mDelivery 請求結果傳遞類

(2). 處理流程圖


這里寫圖片描述
4.2.5 NetworkDispatcher.java

一個線程,用于調度處理走網絡的請求。啟動后會不斷從網絡請求隊列中取請求處理,隊列為空則等待,請求處理結束則將結果傳遞給 ResponseDelivery 去執行后續處理,并判斷結果是否要進行緩存。
(1). 成員變量

BlockingQueue<Request<?>> mQueue 網絡請求隊列
Network mNetwork 網絡類,代表了一個可以執行請求的網絡
Cache mCache 緩存類,代表了一個可以獲取請求結果,存儲請求結果的緩存
ResponseDelivery mDelivery 請求結果傳遞類,可以傳遞請求的結果或者錯誤到調用者

(2). 處理流程圖


這里寫圖片描述
4.2.6 Cache.java

緩存接口,代表了一個可以獲取請求結果,存儲請求結果的緩存。
(1). 主要方法:

public Entry get(String key); 通過 key 獲取請求的緩存實體
public void put(String key, Entry entry); 存入一個請求的緩存實體
public void remove(String key); 移除指定的緩存實體
public void clear(); 清空緩存

(2). 代表緩存實體的內部類 Entry
成員變量和方法

byte[] data 請求返回的數據(Body 實體)
String etag Http 響應首部中用于緩存新鮮度驗證的 ETag
long serverDate Http 響應首部中的響應產生時間
long ttl 緩存的過期時間
long softTtl 緩存的新鮮時間
Map<String, String> responseHeaders 響應的 Headers
boolean isExpired() 判斷緩存是否過期,過期緩存不能繼續使用
boolean refreshNeeded() 判斷緩存是否新鮮,不新鮮的緩存需要發到服務端做新鮮度的檢測
4.2.7 DiskBasedCache.java

繼承 Cache 類,基于 Disk 的緩存實現類。
(1). 主要方法:

public synchronized void initialize() 初始化,掃描緩存目錄得到所有緩存數據摘要信息放入內存。
public synchronized Entry get(String key) 從緩存中得到數據。先從摘要信息中得到摘要信息,然后讀取緩存數據文件得到內容。
public synchronized void put(String key, Entry entry) 將數據存入緩存內。先檢查緩存是否會滿,會則先刪除緩存中部分數據,然后再新建緩存文件。
private void pruneIfNeeded(int neededSpace) 檢查是否能再分配 neededSpace 字節的空間,如果不能則刪除緩存中部分數據。
public synchronized void clear() 清空緩存。 public synchronized void remove(String key) 刪除緩存中某個元素。

(2). CacheHeader 類
CacheHeader 是緩存文件摘要信息,存儲在緩存文件的頭部,與上面的Cache.Entry相似。

4.2.8 NoCache.java

繼承 Cache 類,不做任何操作的緩存實現類,可將它作為構建RequestQueue的參數以實現一個不帶緩存的請求隊列。

4.2.9 Network.java

代表網絡的接口,處理網絡請求。
唯一的方法,用于執行特定請求。

public NetworkResponse performRequest(Request<?> request) throws VolleyError;
4.2.10 NetworkResponse.java

Network中方法 performRequest 的返回值,Request的 parseNetworkResponse(…) 方法入參,是 Volley 中用于內部 Response 轉換的一級。
封裝了網絡請求響應的 StatusCode,Headers 和 Body 等。
(1). 成員變量

int statusCode Http 響應狀態碼
byte[] data Body 數據
Map<String, String> headers 響應 Headers
boolean notModified 表示是否為 304 響應
long networkTimeMs 請求耗時

(2). Volley 的內部 Response 轉換流程圖


這里寫圖片描述

從上到下表示從得到數據后一步步的處理,箭頭旁的注釋表示該步處理后的實體類。

4.2.11 BasicNetwork.java

實現 Network,Volley 中默認的網絡接口實現類。調用HttpStack處理請求,并將結果轉換為可被ResponseDelivery處理的NetworkResponse。
主要實現了以下功能:
(1). 利用 HttpStack 執行網絡請求。
(2). 如果 Request 中帶有實體信息,如 Etag,Last-Modify 等,則進行緩存新鮮度的驗證,并處理 304(Not Modify)響應。
(3). 如果發生超時,認證失敗等錯誤,進行重試操作,直到成功、拋出異常(不滿足重試策略等)結束。

4.2.12 HttpStack.java

用于處理 Http 請求,返回請求結果的接口。目前 Volley 中的實現有基于 HttpURLConnection 的 HurlStack 和 基于 Apache HttpClient 的 HttpClientStack。
唯一方法,執行請求

public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
        throws IOException, AuthFailureError;

執行 Request 代表的請求,第二個參數表示發起請求之前,添加額外的請求 Headers。

4.2.13 HttpClientStack.java

實現 HttpStack 接口,利用 Apache 的 HttpClient 進行各種請求方式的請求。
基本就是 org.apache.http 包下面相關類的常見用法,不做詳解,不過與下面 HttpURLConnection 做下對比就能發現 HttpURLConnection 的 API 相對簡單的多。

4.2.14 HurlStack.java

實現 HttpStack 接口,利用 Java 的 HttpURLConnection 進行各種請求方式的請求。

4.2.15 Response.java

封裝了經過解析后的數據,用于傳輸。并且有兩個內部接口 Listener 和 ErrorListener 分別可表示請求失敗和成功后的回調。
Response 的構造函數被私有化,而通過兩個函數名更易懂的靜態方法構建對象。

4.2.16 ByteArrayPool.java

byte[] 的回收池,用于 byte[] 的回收再利用,減少了內存的分配和回收。 主要通過一個元素長度從小到大排序的ArrayList作為 byte[] 的緩存,另有一個按使用時間先后排序的ArrayList屬性用于緩存滿時清理元素。

public synchronized void returnBuf(byte[] buf)

將用過的 byte[] 回收,根據 byte[] 長度按照從小到大的排序將 byte[] 插入到緩存中合適位置。

public synchronized byte[] getBuf(int len)

獲取長度不小于 len 的 byte[],遍歷緩存,找出第一個長度大于傳入參數len的 byte[],并返回;如果最終沒有合適的 byte[],new 一個返回。

private synchronized void trim()

當緩存的 byte 超過預先設置的大小時,按照先進先出的順序刪除最早的 byte[]。

4.2.17 PoolingByteArrayOutputStream.java

繼承 ByteArrayOutputStream,原始 ByteArrayOutputStream 中用于接受寫入 bytes 的 buf,每次空間不足時便會 new 更大容量的 byte[],而 PoolingByteArrayOutputStream 使用了 ByteArrayPool 作為 Byte[] 緩存來減少這種操作,從而提高性能。

4.2.18 HttpHeaderParser.java

Http header 的解析工具類,在 Volley 中主要作用是用于解析 Header 從而判斷返回結果是否需要緩存,如果需要返回 Header 中相關信息。
有三個方法

public static long parseDateAsEpoch(String dateStr)
解析時間,將 RFC1123 的時間格式,解析成 epoch 時間
public static String parseCharset(Map<String, String> headers)
解析編碼集,在 Content-Type 首部中獲取編碼集,如果沒有找到,默認返回 ISO-8859-1
public static Cache.Entry parseCacheHeaders(NetworkResponse response)
比較重要的方法,通過網絡響應中的緩存控制 Header 和 Body 內容,構建緩存實體。如果 Header 的 Cache-Control 字段含有no-cache或no-store表示不緩存,返回 null。

(1). 根據 Date 首部,獲取響應生成時間
(2). 根據 ETag 首部,獲取響應實體標簽
(3). 根據 Cache-Control 和 Expires 首部,計算出緩存的過期時間,和緩存的新鮮度時間
兩點需要說明下:
1.沒有處理Last-Modify首部,而是處理存儲了Date首部,并在后續的新鮮度驗證時,使用Date來構建If-Modified-Since。 這與 Http 1.1 的語義有些違背。
2.計算過期時間,Cache-Control 首部優先于 Expires 首部。

4.2.19 RetryPolicy.java

重試策略接口
有三個方法:

public int getCurrentTimeout();
獲取當前請求用時(用于 Log)
public int getCurrentRetryCount();
獲取已經重試的次數(用于 Log)
public void retry(VolleyError error) throws VolleyError;
確定是否重試,參數為這次異常的具體信息。在請求異常時此接口會被調用,可在此函數實現中拋出傳入的異常表示停止重試。
4.2.20 DefaultRetryPolicy.java

實現 RetryPolicy,Volley 默認的重試策略實現類。主要通過在 retry(…) 函數中判斷重試次數是否達到上限確定是否繼續重試。
其中mCurrentRetryCount變量表示已經重試次數。
mBackoffMultiplier表示每次重試之前的 timeout 該乘以的因子。
mCurrentTimeoutMs變量表示當前重試的 timeout 時間,會以mBackoffMultiplier作為因子累計前幾次重試的 timeout。

4.2.21 ResponseDelivery.java

請求結果的傳輸接口,用于傳遞請求結果或者請求錯誤。
有三個方法:

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);
此方法用于傳輸請求錯誤。
4.2.22 ExecutorDelivery.java

請求結果傳輸接口具體實現類。
在 Handler 對應線程中傳輸緩存調度線程或者網絡調度線程中產生的請求結果或請求錯誤,會在請求成功的情況下調用 Request.deliverResponse(…) 函數,失敗時調用 Request.deliverError(…) 函數。

4.2.23 StringRequest.java

繼承 Request 類,代表了一個返回值為 String 的請求。將網絡返回的結果數據解析為 String 類型。通過構造函數的 listener 傳參,支持請求成功后的 onResponse(…) 回調。

4.2.24 JsonRequest.java

抽象類,繼承自 Request,代表了 body 為 JSON 的請求。提供了構建 JSON 請求參數的方法。

4.2.25 JsonObjectRequest.java

繼承自 JsonRequest,將網絡返回的結果數據解析為 JSONObject 類型。

4.2.26 JsonArrayRequest.java

繼承自 JsonRequest,將網絡返回的結果數據解析為 JSONArray 類型。

4.2.27 ImageRequest.java

繼承 Request 類,代表了一個返回值為 Image 的請求。將網絡返回的結果數據解析為 Bitmap 類型。
可以設置圖片的最大寬度和最大高度,并計算出合適尺寸返回。每次最多解析一張圖片防止 OOM。

4.2.28 ImageLoader.java

封裝了 ImageRequst 的方便使用的圖片加載工具類。
1.可以設置自定義的ImageCache,可以是內存緩存,也可以是 Disk 緩存,將獲取的圖片緩存起來,重復利用,減少請求。
2.可以定義圖片請求過程中顯示的圖片和請求失敗后顯示的圖片。
3.相同請求(相同地址,相同大小)只發送一個,可以避免重復請求。
// TODO

4.2.29 NetworkImageView.java

利用 ImageLoader,可以加載網絡圖片的 ImageView
有三個公開的方法:

public void setDefaultImageResId(int defaultImage)
設置默認圖片,加載圖片過程中顯示。
public void setErrorImageResId(int errorImage)
設置錯誤圖片,加載圖片失敗后顯示。
public void setImageUrl(String url, ImageLoader imageLoader)
設置網絡圖片的 Url 和 ImageLoader,將利用這個 ImageLoader 去獲取網絡圖片。
如果有新的圖片加載請求,會把這個 ImageView 上舊的加載請求取消。
4.2.30 ClearCacheRequest.java

用于人為清空 Http 緩存的請求。
添加到 RequestQueue 后能很快執行,因為優先級很高,為Priority.IMMEDIATE。并且清空緩存的方法mCache.clear()寫在了isCanceled()方法體中,能最早的得到執行。
ClearCacheRequest 的寫法不敢茍同,目前看來唯一的好處就是可以將清空緩存操作也當做一個請求。而在isCanceled()中做清空操作本身就造成了歧義,不看源碼沒人知道在NetworkDispatcher run 方法循環的過程中,isCanceled()這個讀操作竟然做了可能造成緩存被清空。只能跟源碼的解釋一樣當做一個 Hack 操作。

總結(可以學習的地方):

  1. 兼容性好:默認 Android2.3 及以上基于 HttpURLConnection,2.3 以下基于 HttpClient 實現 (android 2.3以下HttpURLConnection有嚴重bug)
  2. 提供了取消Http 請求的接口,在Activity關閉但是仍舊執行的Http請求可以及時銷毀,減少了性能的開銷以及Activity能夠及時回收。
  3. 使用了多線程(默認4個線程)+ 請求隊列的形式,而不是每次請求都單獨開啟一個線程,減少了性能的開銷。
  4. 支持緩存:在Http協議層(在進行條件請求時,客戶端會提供給服務器一個If-Modified-Since請求頭,其值為服務器上次返回的Last-Modified響應頭中的日期值, 服務器會讀取到這兩個請求頭中的值,判斷出客戶端緩存的資源是否是最新的,如果是的話,服務器就會返回HTTP/304 Not Modified響應)和客戶端都支持cache,大大減少了服務器壓力。同時對客戶端性能開銷也會有一定的減少。
  5. 避免同一個http請求多次連接服務器:如果某個請求已經在等待隊列,并且該請求允許緩存,將該請求放到等待隊列中,使得URI一致的請求不會重復去請求服務器.
  6. 從框架本身的角度來說,Request接口、Cache接口、HttpStack等都是以接口的形式來定義的,充分地展示了Java中面向接口編程的特點,使得代碼的擴展性大大增強

5. 注意事項

Volley 適合于數據量小的并發請求,因為在數據請求完成后,會將請求得到的數據讀到內存中存放在byte[],然后分發給調用者進行數據的轉換。若用volley請求大數據則可能會OOM。
Volley的線程池不具備伸縮功能,創建后所有線程均處于啟用狀態,不支持動態調整。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容