Android框架學習筆記04Volley框架

上一篇中我們學習了Retrofit框架,這一篇我們學習另外一個網絡請求框架——Volley。Volley框架是Google在2013年I/O大會上推出的一個基于HttpUrlconnection封裝的網絡通信框架,上一篇我們學習的Retrofit是基于Okhttp封裝的。Volley將AsyncHttpClient和Universal-Image-Loader的優點集于了一身,我們只需要很簡單的幾句代碼就可以實現網絡通信,我們也不用再關心怎么從網絡獲取圖片、不用關心線程、不用關心圖片資源回收等。Volley除了簡單易用之外,性能也非常好,對于數據量不大,但是操作很頻繁的操作,Volley表現的非常好;但是對于下載文件等大數據量的網絡操作,Volley就不是個很好的選擇了。

概述

一句話概括Volley框架:Volley是Google推出的一個異步的網絡操作和圖片加載框架。

Volley網絡通信操作是基于隊列的,我們只需要把請求添加到請求隊列中就可以了,請求隊列會一次執行請求,一般情況下,應用的網絡操作沒有很多很頻繁,一個Application對應一個請求隊列就可以了;如果是請求網絡操作很多很頻繁,那么可以一個Activity對應一個請求隊列。

Volley框架有以下特征:

  • 自動調度網絡請求

  • 多個并發的網絡連接

  • 通過使用標準的HTTP緩存機制保持磁盤和內存響應的一致

  • 可擴展性:Volley支持請求優先級、支持取消請求(可以取消一個或者多個請求)

  • 健壯性:Volley是面向接口編程,可定制性強

  • 包含調試和追蹤工具

  • 提供簡單易用的圖片加載

我們看一下Volley的總體設計圖

圖片來源于網絡。從上圖中我們可以看出,volley主要是通過兩種Diapatch Thread不斷從RequestQueue中取出請求,根據是否已緩存調用Cache或Network這兩類數據獲取接口之一,從內存緩存或是服務器取得請求的數據,然后交由ResponseDelivery去做結果分發及回調處理。

下面我們通過例子使用一下Volley這個框架:

使用

Volley的基本使用步驟是:

  1. 構建一個RequestQueue。

  2. 創建一個Request,Volley提供的Request有:StringRequest、JsonObjectRequest、JsonArrayRequest、ImageRequest,這四種。

  3. 將Request添加到RequestQueue中。

Volley框架的網絡操作基本是這幾步,下面我們通過實例學習一下Volley的網絡操作。

跟其它框架一樣,需要在AS的Gradle中添加引用:

compile 'com.mcxiaoke.volley:library:1.0.19'

將上面代碼添加到項目的build.gradle中sync就可以了,不過建議先去Volley的GitHub中添加最新的版本,除了添加引用還需要添加網絡訪問的權限。

Google建議我們使用Volley單例工具類,所以我們寫了一個單例工具類

package com.example.frame.common;

import android.content.Context;
import android.graphics.Bitmap;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

/**
 * Created by :Huawen
 * Created time : 2016/9/26 11:16
 * Description :
 * Github: https://github.com/Devin1102
 */

public class VolleyController {
private static VolleyController instance;
private Context mContext;
private ImageLoader mImageLoader;
private RequestQueue mRequestQueue;

private VolleyController(Context mContext) {
    this.mContext = mContext;
    initData();
}

/**
 * 初始化
 */
private void initData() {
    if (mRequestQueue == null) {
        mRequestQueue = Volley.newRequestQueue(mContext);
    }
    if (mImageLoader == null) {
        mImageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() {
            @Override
            public Bitmap getBitmap(String url) {
                return null;
            }

            @Override
            public void putBitmap(String url, Bitmap bitmap) {

            }
        });
    }
}

/**
 * 獲取到VolleyController
 *
 * @param mContext
 * @return
 */
public static synchronized VolleyController getInstance(Context mContext) {
    if (instance == null) {
        instance = new VolleyController(mContext);
    }
    return instance;
}

public RequestQueue getRequestQueue() {
    return mRequestQueue;
}

public ImageLoader getImageLoader() {
    return mImageLoader;
}

public <T> void addToRequestQueue(Request<T> req) {
    getRequestQueue().add(req);
}

}

這里只是一個單例的Volley工具類,提供了過去Volley中RequestQueue和ImageLoader的方法,ImageLoader在我們使用Volley加載圖片的時候用到,所以在這里就添加了一個獲取ImageLoader的方法。

前面我們說過Volley中提供的Request有四種,分別是:StringRequest、JsonObjectRequest、JsonArrayRequest和ImageRequest,下面我們就分別使用這四個Request實現GET請求和POST請求,ImageRequest用于加載圖片。

StringRequest實現GET請求

StringRequest返回的數據是String類型的,StringRequest提供兩個構造方法,我們看一下源碼:

public class StringRequest extends Request<String> {

private Listener<String> mListener;

/**
 * Creates a new request with the given method.
 *
 * @param method the request {@link Method} to use
 * @param url URL to fetch the string at
 * @param listener Listener to receive the String response
 * @param errorListener Error listener, or null to ignore errors
 */
public StringRequest(int method, String url, Listener<String> listener,
        ErrorListener errorListener) {
    super(method, url, errorListener);
    mListener = listener;
}

/**
 * Creates a new GET request.
 *
 * @param url URL to fetch the string at
 * @param listener Listener to receive the String response
 * @param errorListener Error listener, or null to ignore errors
 */
public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
    this(Method.GET, url, listener, errorListener);
}
}

我們可以看到,第一個構造器是多一個參數的,這個參數就是設置請求的方法,第二個構造器沒有method這個請求參數,默認就是GET請求。在StringRequest的構造器中,第一個是設置請求方法,第二個是請求的url,第三個是請求成功的回調,第四個是請求失敗的回調。下面我們看一下實例:

private void stringReqGet() {
    StringRequest stringReqGet = new StringRequest(Request.Method.GET, UrlUtils.GET_BASE_URL,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    Log.i(TAG, "onResponse" + response);
                    Log.i(TAG, "onResponse---stringReqGet---" + getResources().getString(R.string.req_success));
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.i(TAG, "onErrorResponse" + getResources().getString(R.string.req_failed));
        }
    });
    mRequestQueue.add(stringReqGet);
}

如果是GET請求,那么第一個參數可以不指定,默認是GET請求,我們需要實現兩個回調。在一開始的時候我們就說過,Volley是異步的,我們不需要關心線程,請求成功之后更新UI需要通過消息或者其它方式將數據傳遞過去,不能直接在請求回調中更新UI。需要注意的是:只有將請求添加到RequestQueue中,請求才會執行。

StringRequest實現POST請求

Volley框架試下StringRequest的POST請求非常簡單,只需要設置請求方法是POST,然后設置請求參數即可,我們看一下例子源碼:

 private void stringReqPost() {
    StringRequest stringReqPost = new StringRequest(Request.Method.POST, UrlUtils.GET_BASE_URL,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    Log.i(TAG, "onResponse---stringReqPost---" + getResources().getString(R.string.req_success));
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.i(TAG, "onErrorResponse" + getResources().getString(R.string.req_failed));
        }
    }) {
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
            Map<String, String> stringMap = new HashMap<>();
            stringMap.put("username", "Devin");
            stringMap.put("password", "Devin");
            return stringMap;
        }
    };
    mRequestQueue.add(stringReqPost);
}

需要注意的是:請求方法是POST的話,執行請求的時候會調用getParams()方法,所以我們需要在這里設置請求參數,可以使用Map來設置。

JsonObjectRequest實現GET請求

JsonObjectRequest實現GET請求不是很復雜,和StringRequest差不多,我們直接看例子:

private void jsonObjectReqGet() {
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(UrlUtils.GET_BASE_URL,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                    Log.i(TAG, "onResponse" + response.toString());
                    Log.i(TAG, "onResponse" + getResources().getString(R.string.req_success));
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.i(TAG, "onErrorResponse" + getResources().getString(R.string.req_failed));
        }
    });
    mRequestQueue.add(jsonObjectRequest);
}

JsonObjectRequest實現POST請求

private void jsonObjectReqPost() {
    HashMap<String, String> hashMap = new HashMap<>();
    hashMap.put("username", "Devin");
    hashMap.put("password", "Devin");
    JSONObject jsonObject = new JSONObject(hashMap);
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, UrlUtils.GET_BASE_URL,
            jsonObject, new Response.Listener<JSONObject>() {
        @Override
        public void onResponse(JSONObject response) {
            Log.i(TAG, "onResponse" + getResources().getString(R.string.req_success));
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.i(TAG, "onErrorResponse" + getResources().getString(R.string.req_failed));
        }
    }) {

        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            HashMap<String, String> headers = new HashMap<>();
            headers.put("Accept", "application/json");
            headers.put("Content-Type", "application/json; charset=UTF-8");
            return headers;
        }
    };

    mRequestQueue.add(jsonObjectRequest);
}

JsonObjectRequest的POST請求和StringRequest不一樣,在JsonObjectRequest中,我們需要封裝一個JSONObject,當成參數傳遞進去,然后還需要調用getHeaders()方法。JsonObjectRequest有5種構造,這里就不貼代碼了,非常簡單,想要了解的可以自己去看一下源碼。

JsonArrayRequest實現GET請求

private void jsonArrayReqGet() {
    JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, UrlUtils.GET_BASE_URL,
            new Response.Listener<JSONArray>() {
                @Override
                public void onResponse(JSONArray response) {
                    Log.i(TAG, "onResponse" + response.toString());
                    Log.i(TAG, "onResponse" + getResources().getString(R.string.req_success));
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.i(TAG, "onErrorResponse" + getResources().getString(R.string.req_failed));
        }
    });
    mRequestQueue.add(jsonArrayRequest);
}

JsonArrayRequest實現POST請求

private void jsonArrayReqPost() {
    HashMap<String, String> hashMap = new HashMap<>();
    hashMap.put("username", "Devin");
    hashMap.put("password", "Devin");
    JSONArray jsonArray = new JSONArray();
    jsonArray.put(new JSONObject(hashMap));
    JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.POST, UrlUtils.GET_BASE_URL,
            jsonArray, new Response.Listener<JSONArray>() {
        @Override
        public void onResponse(JSONArray response) {
            Log.i(TAG, "onResponse" + getResources().getString(R.string.req_success));
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.i(TAG, "onErrorResponse" + getResources().getString(R.string.req_failed));
        }
    }) {
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            HashMap<String, String> headers = new HashMap<>();
            headers.put("Accept", "application/json");
            headers.put("Content-Type", "application/json; charset=UTF-8");
            return headers;
        }
    };
    mRequestQueue.add(jsonArrayRequest);
}

JsonArrayRequest的POST請求跟JsonObjectRequest的差不多,具體可以看一下構造器。

使用ImageRequest加載圖片

private void loadImage() {
    net_iv.setVisibility(View.INVISIBLE);
    iv_volley.setVisibility(View.VISIBLE);
    ImageRequest imageRequest = new ImageRequest("https://www.baidu.com/img/bd_logo1.png",
            new Response.Listener<Bitmap>() {
                @Override
                public void onResponse(Bitmap response) {
                    iv_volley.setImageBitmap(response);
                    Log.i(TAG, "onResponse" + getResources().getString(R.string.req_success));
                }
            }, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Log.i(TAG, "onErrorResponse" + getResources().getString(R.string.req_failed));
        }
    });
    mRequestQueue.add(imageRequest);
}

從上面的代碼中我們可以看到,我們可以直接在成功的回調中更新UI,非常方便。不過使用ImageRequest加載網絡圖片也逐漸被另外一種方式取代。

使用ImageLoader和NetworkImageView加載圖片

使用ImageLoader和NetworkImageView加載圖片是Volley框架推薦使用的方法,其中NetworkImageView是Volley框架自帶的一個控件,使用非常簡單。

private void imageLoader() {
    String imageUrl = "http://i.weather.com.cn/images/cn/public/2016/09/26/26101505A26375E9BD043626FBA69D86BB7687AC.jpg";
    net_iv.setVisibility(View.VISIBLE);
    iv_volley.setVisibility(View.INVISIBLE);
    ImageLoader mImageLoader = VolleyController.getInstance(getContext()).getImageLoader();
    net_iv.setDefaultImageResId(R.mipmap.ic_menu_icon);
    net_iv.setErrorImageResId(R.mipmap.ic_launcher);
    net_iv.setImageUrl(imageUrl, mImageLoader);
}

使用非常簡單,直接調用setImageUrl()方法就可以了。

這里只是初步使用Volley框架,還有更高級的用法,比如自定義Request等,歡迎大家留言交流!

上面項目的Demo在我的GitHub上,有需要的可以參考參考,GitHub地址

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

推薦閱讀更多精彩內容