一、概述
1. Volley谷歌官方翻譯教程
使用Volley傳輸網絡數據
Volley 是一個HTTP庫,它能夠幫助Android apps更方便的執行網絡操作,最重要的是,它更快速高效。可以通過開源的 AOSP 倉庫獲取到Volley 。發送簡單的網絡請求 (Sending a Simple Request)
學習如何通過Volley默認的行爲發送一個簡單的請求,以及如何取消一個請求。建立請求隊列 (Setting Up a RequestQueue)
學習如何建立一個請求隊列,以及如何實現一個單例模式來創建一個請求隊列,使RequestQueue能夠持續保持在你的app的生命週期中。創建標準的網絡請求 (Making a Standard Request)
學習如何使用Volley的out-of-the-box(可直接使用、無需配置)的請求類型(raw strings, images, and JSON)來發送一個請求。實現自定義的網絡請求 (Implementing a Custom Request)
學習如何實現一個自定義的請求,比如 GsonRequest 。- Volley in GitHub
for Gradle:
compile 'com.mcxiaoke.volley:library:1.0.19'
2. 基於官方教程的一些細節筆記
- Volley使用方式:通過創建一個RequestQueue並傳遞Request對象給它。
- RequestQueue:管理用來執行網絡操作的工作線程,從Cache中讀寫數據,並解析Http的響應內容。
- 請求隊列:可以緩存所有的HTTP請求,然後按照一定的算法併發地發出這些請求。
Requests:執行raw responses的解析,Volley會把響應的數據分發給 主線程。
Volley總是將解析後的數據返回至主線程中。
在主線程中更加合適使用接收到的數據用來操作UI控件,這樣你可以在響應的handler中輕鬆的修改UI。你可以在任何線程中添加一個請求,但是響應結果都是返回到主線程的。
注意那:耗時的操作,例如I/O與解析parsing/decoding都是執行在工作線程。一個請求的生命週期:
對Request對象調用cancel()方法:取消一個請求
- 一旦取消,Volley會確保你的響應Handler不會被執行。
- 這意味着在實際操作中你可以在activity的onStop()方法中取消所有pending在隊列中的請求(通過
stringRequest.setTag(TAG);
中的Tag)。
創建一個單例的RequestQueue,這使得RequestQueue能夠持續保持在你的app的生命週期中。
- 對於ImageLoade來說,單例模式可以避免旋轉所帶來的抖動。
- 使用單例模式可以使得bitmap的緩存與activity的生命週期無關。
- 如果你在activity中創建ImageLoader,這個ImageLoader有可能會在手機進行旋轉的時候被重新創建。這可能會導致抖動。
Volley 的設計目標: 非常適合去進行數據量不大,但通信頻繁的網絡操作,
對於大數據量的網絡操作,比如說下載文件等,Volley的表現就會非常糟糕。
二、使用方法
1. 創建Volley 單例
public class MyApp extends Application {
public static final String TAG = MyApp.class.getSimpleName();
private RequestQueue mRequestQueue;
private ImageLoader mImageLoader;
private static MyApp mInstance;
@Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized MyApp getInstance() {
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
public ImageLoader getImageLoader() {
getRequestQueue();
if (mImageLoader == null) {
mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache());
}
return mImageLoader;
}
public <T> void addToRequestQueue(Request<T> request,String tag) {
request.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
getRequestQueue().add(request);
}
public <T> void addToRequestQueue(Request<T> request) {
request.setTag(TAG);
getRequestQueue().add(request);
}
public void cancelPendingRequests() {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(TAG);
}
}
}
2. 需要一個Cache來緩存請求的圖片:
public class LruBitmapCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache {
public static int getDefaultLruCacheSize() {
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
return cacheSize;
}
public LruBitmapCache(int maxSize) {
super(maxSize);
}
public LruBitmapCache() {
this(getDefaultLruCacheSize());
}
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight() / 1024;
}
@Override
public Bitmap getBitmap(String url) {
return get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
put(url, bitmap);
}
}
三、GET請求
1. 創建json object請求
發送一個請求只要這麼簡單:
- 創建一個JsonRequest對象,寫好response回調接口
- 把這個請求放到請求隊列中就可以了。
JsonArrayRequest也類似。
2. 創建String請求
- StringRequest 可以用來請求任何string類型的數據:
json
,xml
,文本
。
3. 小結
- StringRequest,JsonRequest都是繼承自Request類的
- 不過由於JsonRequest是一個抽象類,我們無法直接創建它的實例,
只能通過它兩個直接的子類JsonObjectRequest
和JsonArrayRequest
入手。
四、POST請求
1. 創建POST請求
與GET請求不同的是:
- 只要在創建請求的時候將請求類型改爲POST請求 :
Method.POST
- 並且重寫Request的
getParams()
方法即可。
@Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("name", "Androidhive");
params.put("email", "[email protected]");
params.put("password", "password123");
return params;
}
2. 添加請求頭部信息
- 重寫
getHeaders()
方法 。
/**
* Passing some request headers
* */
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
headers.put("apiKey", "xxxxxxxxxxxxxxx");
return headers;
}
五、Image請求
1. 用NetworkImageView加載圖片
Volley庫中自帶了NetworkImageView
類,這個ImageView可以 自動 使用volley下載圖片。
原理:
NetworkImageView
加載圖片需要一個ImageLoader
和一個圖片URL
這個ImageLoader
對象需要一個請求隊列對象
和ImageCahe對象
。調用NetworkImageView的
setUrl()
方法後,首先會判斷當前ImageView的URL和新傳入的URL是否一致,- 如果相同,就不用再發送http請求了,
- 如果不同,那麼就使用ImageLoader對象來發送http請求獲取圖片。
ImageLoader imageLoader = MyApp.getInstance().getImageLoader();
// If you are using NetworkImageView
imgNetWorkView.setImageUrl(Const.URL_IMAGE, imageLoader);
2. 用 ImageLoader 和 ImageView來加載圖片
ImageLoader imageLoader = MyApp.getInstance().getImageLoader();
// If you are using normal ImageView
imageLoader.get(Const.URL_IMAGE, new ImageListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 設置爲出錯的圖片
}
@Override
public void onResponse(ImageContainer response, boolean arg1) {
if (response.getBitmap() != null) {
// load image into imageview
imageView.setImageBitmap(response.getBitmap());
}
}
});
- 也可以再簡單一點:
// Loading image with placeholder and error image
imageLoader.get(Const.URL_IMAGE,
ImageLoader.getImageListener(imageView,
R.drawable.ico_loading, R.drawable.ico_error));
ImageLoader.getImageListener()
方法中已經寫了一個默認的ImageListener
了。
2. 用 ImageRequest 和 ImageView來加載圖片
ImageRequest imageRequest = new ImageRequest(
"http://developer.android.com/images/home/aw_dac.png",
new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
imageView.setImageBitmap(response);
}
}, 0, 0, Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
imageView.setImageResource(R.drawable.default_image);
}
});
// 然後在請求隊列中加入這個請求
ImageRequest的構造函數接收六個參數:
- 圖片的URL地址
- 圖片請求成功的回調:
這裏我們把返回的Bitmap參數設置到ImageView中 - 允許圖片最大的寬度
- 允許圖片最大的高度:
如果指定的網絡圖片的寬度或高度大於這裏的最大值,則會對圖片進行壓縮,指定成0的話就表示不管圖片有多大,都不會進行壓縮。 - 指定圖片的顏色屬性:
Bitmap.Config下的幾個常量都可以在這裏使用,其中ARGB_8888可以展示最好的顏色屬性,每個圖片像素佔據4個字節的大小,而RGB_565則表示每個圖片像素佔據2個字節大小。 - 圖片請求失敗的回調:
這裏我們當請求失敗時在ImageView中顯示一張默認圖片。
六、Volley Cache
volley中自帶了強大的cache機制來管理請求cache,這會減少網絡請求次數和用戶等待時間。
1. 從請求Cache中加載請求
Cache cache = MyApp.getInstance().getRequestQueue().getCache();
Entry entry = cache.get(url);
if(entry != null){
try {
String data = new String(entry.data, "UTF-8");
// handle data, like converting it to xml, json, bitmap etc.,
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}else{
// Cached response doesn't exists. Make network call here
}
2. 使請求緩存失效
- 失效並不意味這刪除,
- Volley還會繼續使用緩存的對象直到從服務器上獲取到了新的數據,
- 新的數據會覆蓋舊的數據。
MyApp.getInstance().getRequestQueue().getCache().invalidate(url, true);
3. 關閉Cache
- 如果你想將某一個請求的Cache功能關閉,
- 直接調用Request的
setShouldCache()
方法就可以:
// String request
StringRequest stringReq = new StringRequest(....);
// disable cache
stringReq.setShouldCache(false);
4. 將某一URL的Cache刪除
- 調用Cache的
remove()
方法可以刪除這個URL的cache:
MyApp.getInstance().getRequestQueue().getCache().remove(url);
5. 刪除所有的Cache
- 使用Cache的
clear()
方法:
MyApp.getInstance().getRequestQueue().getCache().clear();
6. 取消請求
在添加請求到請求隊列中的時候,可以現,
addToRequestQueue(request, tag)
方法還接受一個tag參數,
這個tag就是用來標記某一類請求的,這樣就可以取消這個tag的所有請求了:
static final String TAG = "json_req";
MyApp.getInstance().getRequestQueue().cancelAll(TAG);
七、請求優先級
在創建一個request時
可以重寫 Request方法的getPriority()
方法返回一個優先級,
優先級分爲:Normal
, Low
, High
,Immediate
。
private Priority priority = Priority.HIGH;
StringRequest strReq = new StringRequest(Method.GET,
Const.URL_STRING_REQ, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d(TAG, response.toString());
msgResponse.setText(response.toString());
hideProgressDialog();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
hideProgressDialog();
}
}) {
@Override
public Priority getPriority() {
return priority;
}
};
參考文章:
1. Android庫Volley的使用介紹
2. Android Volley完全解析(二),使用Volley加載網絡圖片
3. Android Volley完全解析(三),定製自己的Request
4. Android Volley完全解析(四),帶你從源碼的角度理解Volley