Volley主頁 https://android.googlesource.com/platform/frameworks/volley
html
http://www.youtube.com/watch?v=yhv8l9F44qo&feature=player_embedded
java
Google I/O 2013上。Volley公佈了volley。在這以前,咱們在程序中需要和網絡通訊的時候,大致使用的東西莫過於android
Volley是Android平臺上的網絡通訊庫。能使網絡通訊更快,更簡單,更健壯。git
Volley名稱的由來: a burst or emission of many things or a large amount at oncegithub
在Google IO的演講上。其配圖是一幅發射火弓箭的圖。有點相似流星。見下圖
事實上。從這幅圖,咱們也可以看出來,Volley特別適合數據量不大但是通訊頻繁的場景。volley適合高速,簡單的請求(Json對象,圖片載入)。json
在曾經,咱們可能面臨例如如下很是多麻煩的問題。緩存
比方曾經從網上下載圖片的步驟多是這種流程:網絡
而在Volley下,僅僅需要一個函數就能夠,具體見後面的樣例。架構
再比方,屏幕旋轉的時候,有時候會致使再次從網絡取得數據。爲了不這樣的沒必要要的網絡訪問,咱們可能需要本身寫很是多針對各類狀況的處理。比方cache什麼的。app
再有。比方ListView的時候,咱們滾動過快,可能致使有些網絡請求返回的時候,早已經滾過了當時的位置,根本不是必需顯示在list裏了,儘管咱們可以經過ViewHolder來保持url等來實現防止兩次取得,但是那些已經沒有必須要的數據。仍是會浪費系統的各類資源。
簡單來講,它提供了例如如下的便利功能:
引入Volley很easy,首先,從git庫先克隆一個下來:
git clone https://android.googlesource.com/platform/frameworks/volleyview
而後編譯爲jar包,再在本身的project裏import進來。
注意。這個庫要求最低SDK版本號爲Froyo,即至少要設置android:minSdkVersion爲8以上。
這個樣例很是easy,從網絡取得JSON對象,而後打印出來。
mQueue = Volley.newRequestQueue(getApplicationContext()); mQueue.add(new JsonObjectRequest(Method.GET, url, null, new Listener() { @Override public void onResponse(JSONObject response) { Log.d(TAG, "response : " + response.toString()); } }, null)); mQueue.start();
// imageView是一個ImageView實例 // ImageLoader.getImageListener的第二個參數是默認的圖片resource id // 第三個參數是請求失敗時候的資源id,可以指定爲0 ImageListener listener = ImageLoader.getImageListener(imageView, android.R.drawable.ic_menu_rotate, android.R.drawable.ic_delete); mImageLoader.get(url, listener);ImageLoader的方法都需要從主線程裏來調用。
Volley提供了一個新的控件NetworkImageView來取代傳統的ImageView,這個控件的圖片屬性可以經過
mImageView.setImageUrl(url, imageLoader)來設定。而且,這個控件在被從父控件detach的時候,會本身主動取消網絡請求的。即全然不用咱們操心相關網絡請求的生命週期問題。
mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache()); ... ... if(holder.imageRequest != null) { holder.imageRequest.cancel(); } holder.imageRequest = mImageLoader.get(BASE_UR + item.image_url, holder.imageView, R.drawable.loading, R.drawable.error);
注意,這裏使用的不是ImageView控件。而是Volley新提供的com.android.volley.NetworkImageView。
另外,注意這裏:
mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache()); <span style="color:#000000;"><a target=_blank target="_blank" href="http://blog.csdn.net/t12x3456/article/details/9221611#" class="ViewSource" title="view plain" style="text-decoration: none; background-color: inherit; border: medium none; padding: 1px; margin: 0px 10px 0px 0px; font-size: 9px; display: inline-block; width: 16px; height: 16px; text-indent: -2000px;">ew plain</a></span>
/** * Simple cache adapter interface. If provided to the ImageLoader, it * will be used as an L1 cache before dispatch to Volley. Implementations * must not block. Implementation with an LruCache is recommended. */ public interface ImageCache { public Bitmap getBitmap(String url); public void putBitmap(String url, Bitmap bitmap); }
咱們也可以經過繼承Request依據本身的需求來定製本身的request
@Override protected Response parseNetworkResponse(NetworkResponse response) { try { String json = new String( response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success( gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JsonSyntaxException e) { return Response.error(new ParseError(e)); } }
裏面使用的gson(com.google.gson.Gson)是JSON的序列化和反序列化的庫,可以在JSON和java model object之間進行轉換。
下面是使用自定製request的樣例:
mRequestQueue.add( new GsonRequest(url, ListResponse.class, null, new Listener() { public void onResponse(ListResponse response) { appendItemsToList(response.item); notifyDataSetChanged(); } } }
Volley使用了線程池來做爲基礎結構,主要分爲主線程。cache線程和network線程。
主線程和cache線程都僅僅有一個。而NetworkDispatcher線程可以有多個。這樣能解決比並行問題。
例如如下圖:
其中藍色部分表明主線程,綠色部分表明緩存線程,橙色部分表明網絡線程。咱們在主線程中調用RequestQueue的add()方法來增長一條網絡請求。這條請求會先被增長到緩存隊列其中,假設發現可以找到對應的緩存結果就直接讀取緩存並解析。而後回調給主線程。假設在緩存中沒有找到結果,則將這條請求增長到網絡請求隊列中,而後處理髮送HTTP請求,解析響應結果,寫入緩存,並回調主線程。
假設在一個Activity裏面啓動了網絡請求,而在這個網絡請求還沒返回結果的時候。假設Activity被結束了。則咱們需要寫例如如下代碼做爲防守:
@Override public void onPostExecute(Result r) { if (getActivity() == null) { return; } // ... }
Activity被終止以後,假設繼續使用當中的Context等,除了無辜的浪費CPU,電池,網絡等資源。有可能還會致使程序crash,因此,咱們需要處理這樣的一場狀況。
使用Volley的話,咱們可以在Activity中止的時候,同一時候取消所有或部分未完畢的網絡請求。
Volley裏所有的請求結果會返回給主進程。假設在主進程裏取消了某些請求,則這些請求將不會被返回給主線程。
比方。可以針對某些個request作取消操做y
@Override public void onStop() { for (Request <?或者,取消這個隊列裏的所有請求:> req : mInFlightRequests) { req.cancel(); } ... }
@Override pubic void onStop() { mRequestQueue.cancelAll(this); ... }
@Override public void onStop() { mRequestQueue.cancelAll( new RequestFilter() {}) ... // or mRequestQueue.cancelAll(new Object()); ...
從演講的樣例來看。Volley應該是簡化了網絡通訊的一些開發,特別是針對例如如下兩種狀況:
但是這個東西也有不有用的地方,比方大數據(large payloads ),流媒體,這些case,還需要使用原始的方法,比方Download Manager等。
接下來,咱們來學習簡單的使用下volley給我提供的API吧。
(RequestQueue僅僅需要一個實例就能夠,不像AsyncTask每次使用都要new一個)
// 初始化RequestQueue一個activity僅僅需要一個
private void initRequestQueue() {
mQueue = Volley.newRequestQueue(getApplicationContext());
}
(JsonObjectRequest,JsonArrayRequest,StringRequest,ImageRequest)
由於使用方法都相差不大。我就不一一舉例了。舉幾個常用有表明性的樣例:
// post請求
private void loadPostJson(String url) {
// 第二個參數說明:
// Constructor which defaults to GET if jsonRequest is null, POST
// otherwise.
// 默認狀況下設成null爲get方法,不然爲post方法。
JsonObjectRequest srReq = new JsonObjectRequest(url, null,
new JsonListener(), new StrErrListener()) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> map = new HashMap<String, String>();
map.put("w", "2459115");
map.put("u", "f");
return map;
}
};
srReq.setShouldCache(false); // 控制是否緩存
startVolley(srReq);
}
// Str請求成功回調 private class StrListener implements Listener<String> { @Override public void onResponse(String arg0) { Log.e(Tag, arg0); } } // Gson請求成功回調 private class GsonListener implements Listener<ErrorRsp> { @Override public void onResponse(ErrorRsp arg0) { Toast.makeText(mContext, arg0.toString(), Toast.LENGTH_LONG).show(); } } // 共用失敗回調 private class StrErrListener implements ErrorListener { @Override public void onErrorResponse(VolleyError arg0) { Toast.makeText(mContext, VolleyErrorHelper.getMessage(arg0, mContext), Toast.LENGTH_LONG).show(); } }
/** * 第三第四個參數分別用於指定贊成圖片最大的寬度和高度。假設指定的網絡圖片的寬度或高度大於這裏的最大值。則會對圖片進行壓縮, * 指定成0的話就表示不管圖片有多大。都不會進行壓縮。 * * @param url * 圖片地址 * @param listener * @param maxWidth * 指定贊成圖片最大的寬度 * @param maxHeight * 指定贊成圖片最大的高度 * @param decodeConfig * 指定圖片的顏色屬性。Bitmap.Config下的幾個常量. * @param errorListener */ private void getImageRequest(final ImageView iv, String url) { ImageRequest imReq = new ImageRequest(url, new Listener<Bitmap>() { @Override public void onResponse(Bitmap arg0) { iv.setImageBitmap(arg0); } }, 60, 60, Bitmap.Config.ARGB_8888, new StrErrListener()); startVolley(imReq); }
// 加入及開始請求 private void startVolley(Request req) { // 設置超時時間 // req.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f)); // 將請求加入隊列 mQueue.add(req); // 開始發起請求 mQueue.start(); }
volley不只提供了這些請求的方式。還提供了載入圖片的一些方法和控件:
比方咱們一個列表需要載入很是多圖片咱們可以使用volley給咱們提供的ImageLoader( ImageLoader比ImageRequest更加高效,因爲它不只對圖片進行緩存。還可以過濾掉反覆的連接。避免反覆發送請求。
)
public class ImageAdapter extends ArrayAdapter<String> {
private RequestQueue mQueue;
private ImageLoader mImageLoader;
public ImageAdapter(Context context, List<String> objects) {
super(context, 0, objects);
mQueue = Volley.newRequestQueue(getContext());
mImageLoader = new ImageLoader(mQueue, new BitmapCache());
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
String url = getItem(position);
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(getContext());
} else {
imageView = (ImageView) convertView;
}
// getImageListener(imageView控件對象。默認圖片地址。失敗圖片地址);
ImageListener listener = ImageLoader.getImageListener(imageView, android.R.drawable.ic_menu_rotate, android.R.drawable.ic_delete);
// get(圖片地址。listener。寬,高);本身主動幫你處理圖片的寬高不再怕大圖片的oom了
mImageLoader.get(url, listener,100,200);
return imageView;
}
}
public class <span style="font-family: Arial;">BitmapCache</span><span style="font-family: Arial;"> extends LruCache<String, Bitmap> implements ImageCache {</span> // LruCache 原理:Cache保存一個強引用來限制內容數量,每當Item被訪問的時候,此Item就會移動到隊列的頭部。 當cache已滿的時候增長新的item時,在隊列尾部的item會被回收。 // 解釋:當超出指定內存值則移除近期最少用的圖片內存 public static int getDefaultLruCacheSize() { // 拿到最大內存 final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); // 拿到內存的八分之中的一個來作圖片內存緩存 final int cacheSize = maxMemory / 8; return cacheSize; } public BitmapLruCache() { this(getDefaultLruCacheSize()); } public BitmapLruCache(int sizeInKiloBytes) { super(sizeInKiloBytes); } @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); } }
<com.android.volley.toolbox.NetworkImageView android:id="@+id/network_image_view" android:layout_width="100dp" android:layout_height="100dp" />
private void networkImageViewUse(NetworkImageView iv, String url) { ImageLoader imLoader = new ImageLoader(mQueue, new BitmapLruCache()); iv.setDefaultImageResId(R.drawable.ic_launcher); iv.setErrorImageResId(R.drawable.ic_launcher); iv.setImageUrl(url, imLoader); }
1.activity本身主動銷燬時它會自定取消所有請求。
2.給請求設置標籤:
request.setTag("My Tag");
取消所有指定標記的請求: