Android網路框架Volley
他們各有優劣,之前個人則比較喜歡用android-async-http, 如今Google推出了官方的針對Android平臺上的網路通訊庫,能使網路通訊更快,更簡單,更健壯,Volley在提供了高效能網路通訊功能的同時,對網路圖片載入也提供了良好的支援,完全可以滿足簡單REST客戶端的需求, 我們沒有理由不跟上時代的潮流
使用Volley
下載Volley原始碼並build jar包。
$ git clone https://android.googlesource.com/platform/frameworks/volley$ cd volley$ android update project -p$ ant jar
然後把生成的jar包引用到我們的專案中,extras目錄下則包含了目前最新的volley原始碼。
說明
此Demo主要介紹了日常網路開發常用的基本功能,但volley的擴充套件性很強,可以根據需要定製你自己的網路請求。
以上是在Google IO的演講上ppt的配圖,從上面這張圖我們可以看出,volley適合快速,簡單的請求(Json物件,圖片載入)。
volley的特性:
- JSON,影象等的非同步下載;
- 網路請求的排序(scheduling)
- 網路請求的優先順序處理
- 快取
- 多級別取消請求
- 和Activity和生命週期的聯動(Activity結束時同時取消所有網路請求)
接下來,我們來學習簡單的使用下volley給我提供的API吧。
1.首先拿到一個請求佇列(RequestQueue只需要一個例項即可,不像AsyncTask每次使用都要new一個)
[java] view plaincopyprint?- // 初始化RequestQueue一個activity只需要一個
- privatevoid initRequestQueue() {
- mQueue = Volley.newRequestQueue(getApplicationContext());
- }
由於用法都相差不大,我就不一一舉例了,舉幾個常用有代表性的例子:
以下程式碼是StringRequest的get請求:
[java] view plaincopyprint?- // get請求
- privatevoid loadGetStr(String url) {
- StringRequest srReq = new StringRequest(Request.Method.GET, url,
- new StrListener(), new StrErrListener()) {
- protectedfinal String TYPE_UTF8_CHARSET = "charset=UTF-8";
- // 重寫parseNetworkResponse方法改變返回頭引數解決亂碼問題
- // 主要是看伺服器編碼,如果伺服器編碼不是UTF-8的話那麼就需要自己轉換,反之則不需要
- @Override
- protected Response<String> parseNetworkResponse(
- NetworkResponse response) {
- try {
- String type = response.headers.get(HTTP.CONTENT_TYPE);
- if (type == null) {
- type = TYPE_UTF8_CHARSET;
- response.headers.put(HTTP.CONTENT_TYPE, type);
- } elseif (!type.contains("UTF-8")) {
- type += ";" + TYPE_UTF8_CHARSET;
- response.headers.put(HTTP.CONTENT_TYPE, type);
- }
- } catch (Exception e) {
- }
- returnsuper.parseNetworkResponse(response);
- }
- };
- srReq.setShouldCache(true); // 控制是否快取
- startVolley(srReq);
- }
- // post請求
- privatevoid 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請求成功回撥
- privateclass StrListener implements Listener<String> {
- @Override
- publicvoid onResponse(String arg0) {
- Log.e(Tag, arg0);
- }
- }
- // Gson請求成功回撥
- privateclass GsonListener implements Listener<ErrorRsp> {
- @Override
- publicvoid onResponse(ErrorRsp arg0) {
- Toast.makeText(mContext, arg0.toString(), Toast.LENGTH_LONG).show();
- }
- }
- // 共用失敗回撥
- privateclass StrErrListener implements ErrorListener {
- @Override
- publicvoid 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
- */
- privatevoid getImageRequest(final ImageView iv, String url) {
- ImageRequest imReq = new ImageRequest(url, new Listener<Bitmap>() {
- @Override
- publicvoid onResponse(Bitmap arg0) {
- iv.setImageBitmap(arg0);
- }
- }, 60, 60, Bitmap.Config.ARGB_8888, new StrErrListener());
- startVolley(imReq);
- }
- // 新增及開始請求
- privatevoid startVolley(Request req) {
- // 設定超時時間
- // req.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));
- // 將請求加入佇列
- mQueue.add(req);
- // 開始發起請求
- mQueue.start();
- }
volley不僅提供了這些請求的方式,還提供了載入圖片的一些方法和控制元件:
比如我們一個列表需要載入很多圖片我們可以使用volley給我們提供的ImageLoader( ImageLoader比ImageRequest更加高效,因為它不僅對圖片進行快取,還可以過濾掉重複的連結,避免重複傳送請求。)
[java] view plaincopyprint?- publicclass 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;
- }
- }
- publicclass <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會被回收。
- // 解釋:當超出指定記憶體值則移除最近最少用的圖片記憶體
- publicstaticint getDefaultLruCacheSize() {
- // 拿到最大記憶體
- finalint maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
- // 拿到記憶體的八分之一來做圖片記憶體快取
- finalint cacheSize = maxMemory / 8;
- return cacheSize;
- }
- public BitmapLruCache() {
- this(getDefaultLruCacheSize());
- }
- public BitmapLruCache(int sizeInKiloBytes) {
- super(sizeInKiloBytes);
- }
- @Override
- protectedint sizeOf(String key, Bitmap value) {
- return value.getRowBytes() * value.getHeight() / 1024;
- }
- @Override
- public Bitmap getBitmap(String url) {
- return get(url);
- }
- @Override
- publicvoid 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"/>
- privatevoid 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.給請求設定標籤:
[java] view plaincopyprint?- request.setTag("My Tag");
取消所有指定標記的請求:
[java] view plaincopyprint?- request.cancelAll("My Tag");
其中藍色部分代表主執行緒,綠色部分代表快取執行緒,橙色部分代表網路執行緒。我們在主執行緒中呼叫RequestQueue的add()方法來新增一條網路請求,這條請求會先被加入到快取隊列當中,如果發現可以找到相應的快取結果就直接讀取快取並解析,然後回撥給主執行緒。如果在快取中沒有找到結果,則將這條請求加入到網路請求佇列中,然後處理髮送HTTP請求,解析響應結果,寫入快取,並回調主執行緒。
接下來我們要看看如何把volley使用到實戰專案裡面,我們先考慮下一些問題:
從上一篇來看 mQueue 只需要一個物件即可,new RequestQueue物件對資源一種浪費,我們應該在application,以及可以把取消請求的方法也在application進行統一管理,看以下程式碼:
[java] view plaincopyprint?- package com.chronocloud.lib.base;
- import android.app.Application;
- import android.text.TextUtils;
- import com.android.volley.Request;
- import com.android.volley.RequestQueue;
- import com.android.volley.VolleyLog;
- import com.android.volley.toolbox.Volley;
- publicclass ApplicationController extends Application {
- /**
- * Log or request TAG
- */
- publicstaticfinal String TAG = "VolleyPatterns";
- /**
- * Global request queue for Volley
- */
- private RequestQueue mRequestQueue;
- /**
- * A singleton instance of the application class for easy access in other
- * places
- */
- privatestatic ApplicationController sInstance;
- @Override
- publicvoid onCreate() {
- super.onCreate();
- // initialize the singleton
- sInstance = this;
- }
- /**
- * @return ApplicationController singleton instance
- */
- publicstaticsynchronized ApplicationController getInstance() {
- return sInstance;
- }
- /**
- * @return The Volley Request queue, the queue will be created if it is null
- */
- public RequestQueue getRequestQueue() {
- // lazy initialize the request queue, the queue instance will be
- // created when it is accessed for the first time
- if (mRequestQueue == null) {
- // 1
- // 2
- synchronized (ApplicationController.class) {
- if (mRequestQueue == null) {
- mRequestQueue = Volley
- .newRequestQueue(getApplicationContext());
- }
- }
- }
- return mRequestQueue;
- }
- /**
- * Adds the specified request to the global queue, if tag is specified then
- * it is used else Default TAG is used.
- *
- * @param req
- * @param tag
- */
- public <T> void addToRequestQueue(Request<T> req, String tag) {
- // set the default tag if tag is empty
- req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
- VolleyLog.d("Adding request to queue: %s", req.getUrl());
- getRequestQueue().add(req);
- }
- /**
- * Adds the specified request to the global queue using the Default TAG.
- *
- * @param req
- * @param tag
- */
- public <T> void addToRequestQueue(Request<T> req) {