Android:Volley的使用及其工具類的封裝

jopen 8年前發布 | 172K 次閱讀 Volley Android開發 移動開發

一. Volley簡介

Volley的中文翻譯為“齊射、并發”,是在2013年的Google大會上發布的一款Android平臺網絡通信庫,具有網絡請求的處理、小圖片的異步加載和緩存等功能,能夠幫助 Android APP 更方便地執行網絡操作,而且更快速高效。

在Google IO的演講上,其配圖是一幅發射火弓箭的圖,有點類似流星。這表示,Volley特別適合數據量不大但是通信頻繁的場景。見下圖:

Volley 有如下的優點:

  • 自動調度網絡請求;
  • 高并發網絡連接;
  • 通過標準的 HTTP cache coherence(高速緩存一致性)緩存磁盤和內存透明的響應;
  • 支持指定請求的優先級;
  • 網絡請求cancel機制。我們可以取消單個請求,或者指定取消請求隊列中的一個區域;
  • 框架容易被定制,例如,定制重試或者回退功能;
  • 包含了調試與追蹤工具;

Volley 不適合用來下載大的數據文件。因為 Volley 會保持在解析的過程中所有的響應。對于下載大量的數據操作,請考慮使用 DownloadManager。

在volley推出之前我們一般會選擇比較成熟的第三方網絡通信庫,如:android-async-http、retrofit、okhttp等。他們各有優劣,可有所斟酌地選擇選擇更適合項目的類庫。

附錄:

Volley的github地址: https://github.com/mcxiaoke/android-volley

Google I/O 2013 – Volley: Easy, Fast Networking for Android: https://www.油Tube.com/watch?v=yhv8l9F44qo&feature=player_embedded

二. Volley jar包的導入

Volley 框架的核心代碼是托管在 AOSP 倉庫 的 frameworks/volley 中,相關的工具放在 toolbox 下。

把 Volley 添加到項目中最簡便的方法是 Clone 倉庫,然后把它設置為一個 library project。

1) clone代碼:

>git clone https://android.googlesource.com/platform/frameworks/volley

2)將代碼編譯成jar包:

android update project -p . ant jar

如無意外,將獲得volley.jar包。

3)添加volley.jar到你的項目中:

可參考: http://jingyan.baidu.com/article/e6c8503c7190b7e54f1a1893.html

備注:

附上我的volley.jar包的地址: http://pan.baidu.com/s/1sjSwCrV ,方便大家直接下載使用。當然,Volley更新較快,還是希望大家能直接通過clone代碼后進行編譯。

三. Volley框架的詳細使用:

Volley工作原理圖如下:

Android:Volley的使用及其工具類的封裝

使用Volley框架實現網絡數據請求主要有以下三個步驟:

  • 1.創建RequestQueue對象,定義網絡請求隊列;
  • 2.創建XXXRequest對象(XXX代表String,JSON,Image等等),定義網絡數據請求的詳細過程;
  • 3.把XXXRequest對象添加到RequestQueue中,開始執行網絡請求。

3.1 創建RequestQueue對象

一般而言,網絡請求隊列都是整個APP內使用的全局性對象,因此最好寫入Application類中:

>public class MyApplication extends Application{
    // 建立請求隊列
    public static RequestQueue queue;

    @Override
    public void onCreate() {
        super.onCreate();
        queue = Volley.newRequestQueue(getApplicationContext());
    }

    public static RequestQueue getHttpQueue() {
        return queue;
    }
}

這是,我們還需要修改AndroidManifest.xml文件,使APP的Application對象為我們剛定義的MyApplication,并添加INTERNET權限:

><uses-permission android:name="android.permission.INTERNET" />
<application
    android:name=".MyApplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme" >
</application>

3.2 創建XXXRequest對象并添加到請求隊列中

Volley提供了JsonObjectRequest、JsonArrayRequest、StringRequest等Request形式:

  • JsonObjectRequest:返回JSONObject對象;
  • JsonArrayRequest:返回JsonArray對象;
  • StringRequest:返回String。

另外可以繼承Request自定義Request。

>public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // GET請求
        VolleyGet();

        // POST請求
        VolleyPost();
    }

    // 定義POST請求的方法
    private void VolleyPost() {
        // 請求地址
        String url = "http://ce.sysu.edu.cn/hope/";

        // 創建StringRequest,定義字符串請求的請求方式為POST,
        StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
            // 請求成功后執行的函數
            @Override
            public void onResponse(String s) {
                // 打印出POST請求返回的字符串
                Toast.makeText(MainActivity.this, "POST: " + s, Toast.LENGTH_LONG).show();
            }
        }, new Response.ErrorListener() {
            // 請求失敗時執行的函數
            @Override
            public void onErrorResponse(VolleyError volleyError) {

            }
        }){

            // 定義請求數據
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> hashMap = new HashMap<String, String>();
                hashMap.put("phone", "11111");
                return hashMap;
            }
        };
        // 設置該請求的標簽
        request.setTag("abcPost");

        // 將請求添加到隊列中
        MyApplication.getHttpQueue().add(request);
    }

    // 定義GET請求的方法
    private void VolleyGet() {
        // 定義請求地址
        String url = "http://ce.sysu.edu.cn/hope/";
        StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
            @Override
            public void onResponse(String s) {
                // 打印出GET請求返回的字符串
                Toast.makeText(MainActivity.this, s, Toast.LENGTH_LONG).show();
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {

            }
        });

        // 設置該請求的標簽
        request.setTag("abcGet");

        // 將請求添加到隊列中
        MyApplication.getHttpQueue().add(request);
    }
}

輸出:

>// POST請求
POST: <厚樸網站首頁源代碼。。。>
// GET請求
GET: <厚樸網站首頁源代碼。。。>

3.3 關閉請求

3.3.1 關閉特定標簽的網絡請求:

>// 網絡請求標簽為"abcGet"
public void onStop() {
    super.onStop();
    MyApplication.getHttpQueues.cancelAll("abcGet");
}

3.3.2 取消這個隊列里的所有請求:

在activity的onStop()方法里面,取消所有的包含這個tag的請求任務。

>@Override  
protected void onStop() {  
    super.onStop();  
    mRequestQueue.cancelAll(this);  
}

四. GET和POST請求工具庫的封裝

4.1 重寫Application

因為網絡請求隊列相對于APP應用老說是全局對象,因此可以定義在全局中。為此,我們新建一個LIMSApplication,并讓其繼承自Application。

LIMSApplication.java文件:

>public class LIMSApplication extends Application {
    public static RequestQueue volleyQueue;
    @Override
    public void onCreate() {
        super.onCreate();

        /* Volley配置 */
        // 建立Volley的Http請求隊列
        volleyQueue = Volley.newRequestQueue(getApplicationContext());
    }

    // 開放Volley的HTTP請求隊列接口
    public static RequestQueue getRequestQueue() {
        return volleyQueue;
    }
}

不要忘記在AndroidManifest.xml文件中修改Application的name和相應的網絡請求權限:

><uses-permission android:name="android.permission.INTERNET" />
<application
    android:name=".LIMSApplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme" >
</application>

4.2 GET和POST請求的封裝:

目前,VolleyRequestUtil工具庫只包含了兩個函數,分別獲取GET和POST請求。

VolleyRequestUtil.java:

>public class VolleyRequestUtil {

    public static StringRequest stringRequest;
    public static Context context;

    /*
    * 獲取GET請求內容
    * 參數:
    * context:當前上下文;
    * url:請求的url地址;
    * tag:當前請求的標簽;
    * volleyListenerInterface:VolleyListenerInterface接口;
    * */
    public static void RequestGet(Context context, String url, String tag, VolleyListenerInterface volleyListenerInterface) {
        // 清除請求隊列中的tag標記請求
        LIMSApplication.getRequestQueue().cancelAll(tag);
        // 創建當前的請求,獲取字符串內容
        stringRequest = new StringRequest(Request.Method.GET, url, volleyListenerInterface.responseListener(), volleyListenerInterface.errorListener());
        // 為當前請求添加標記
        stringRequest.setTag(tag);
        // 將當前請求添加到請求隊列中
        LIMSApplication.getRequestQueue().add(stringRequest);
        // 重啟當前請求隊列
        LIMSApplication.getRequestQueue().start();
    }

    /*
    * 獲取POST請求內容(請求的代碼為Map)
    * 參數:
    * context:當前上下文;
    * url:請求的url地址;
    * tag:當前請求的標簽;
    * params:POST請求內容;
    * volleyListenerInterface:VolleyListenerInterface接口;
    * */
    public static void RequestPost(Context context, String url, String tag, final Map<String, String> params, VolleyListenerInterface volleyListenerInterface) {
        // 清除請求隊列中的tag標記請求
        LIMSApplication.getRequestQueue().cancelAll(tag);
        // 創建當前的POST請求,并將請求內容寫入Map中
        stringRequest = new StringRequest(Request.Method.POST, url, volleyListenerInterface.responseListener(), volleyListenerInterface.errorListener()){
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                return params;
            }
        };
        // 為當前請求添加標記
        stringRequest.setTag(tag);
        // 將當前請求添加到請求隊列中
        LIMSApplication.getRequestQueue().add(stringRequest);
        // 重啟當前請求隊列
        LIMSApplication.getRequestQueue().start();
    }
}

4.3 Volley請求(成功或失敗)的監聽事件封裝:

封裝Volley請求(成功或失敗)的監聽事件,見VolleyListenerInterface.java:

>public abstract class VolleyListenerInterface {
    public Context mContext;
    public static Response.Listener<String> mListener;
    public static Response.ErrorListener mErrorListener;

    public VolleyListenerInterface(Context context, Response.Listener<String> listener, Response.ErrorListener errorListener) {
        this.mContext = context;
        this.mErrorListener = errorListener;
        this.mListener = listener;
    }

    // 請求成功時的回調函數
    public abstract void onMySuccess(String result);

    // 請求失敗時的回調函數
    public abstract void onMyError(VolleyError error);

    // 創建請求的事件監聽
    public Response.Listener<String> responseListener() {
        mListener = new Response.Listener<String>() {
            @Override
            public void onResponse(String s) {
                onMySuccess(s);
            }
        };
        return mListener;
    }

    // 創建請求失敗的事件監聽
    public Response.ErrorListener errorListener() {
        mErrorListener = new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                onMyError(volleyError);
            }
        };
        return mErrorListener;
    }
}

4.3 Volley圖片加載庫的封裝:

Volley庫還具有圖片加載的功能。但適合小圖片的異步加載,不適合于比較大的圖片資源的請求。

Volley提供了多種Request方法,譬如ImageRequest、ImageLoader、NetWorkImageView。

網絡圖片資源的請求封裝如下:

ImageLoaderUtil.java:

>public class ImageLoaderUtil {

    /*
    * 通過ImageRequest來顯示網絡圖片
    * */
    public static void setImageRequest(String url, final ImageView imageView) {
        ImageRequest imageRequest = new ImageRequest(url, new Response.Listener<Bitmap>() {
            @Override
            public void onResponse(Bitmap bitmap) {
                imageView.setImageBitmap(bitmap);
            }
        }, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                imageView.setBackgroundResource(R.mipmap.ic_launcher);
            }
        });
        LIMSApplication.getRequestQueue().add(imageRequest);
    }

    /*
    * 通過ImageLoader來顯示網絡圖片
    * */
    public static void setImageLoader(String url, ImageView imageView, int defaultImageResId, int errorImageResId) {
        ImageLoader loader = new ImageLoader(LIMSApplication.getRequestQueue(), new BitmapCache());
        ImageLoader.ImageListener imageListener = ImageLoader.getImageListener(imageView, defaultImageResId, errorImageResId);
        loader.get(url, imageListener);
    }

    /*
    * 通過Volley的NetWorkImageView來顯示網絡圖片
    * */
    public static void setNetWorkImageView(String url, NetworkImageView netWorkImageView, int defaultImageResId, int errorImageResId) {
        ImageLoader loader = new ImageLoader(LIMSApplication.getRequestQueue(), new BitmapCache());

        netWorkImageView.setDefaultImageResId(defaultImageResId);
        netWorkImageView.setErrorImageResId(errorImageResId);
        netWorkImageView.setImageUrl(url, loader);
    }
}

五. VolleyRequestUtil與ImageLoaderUtil的使用

5.1 用GET方式請求網絡資源:

>new VolleyRequestUtil().RequestGet(this, "http://ce.sysu.edu.cn/hope/", "hopePage", 
    new VolleyListenerInterface(this, VolleyListenerInterface.mListener, VolleyListenerInterface.mErrorListener) {
    // Volley請求成功時調用的函數
    @Override
    public void onMySuccess(String result) {
        Toast.makeText(this, s, Toast.LENGTH_LONG).show();
    }

    // Volley請求失敗時調用的函數
    @Override
    public void onMyError(VolleyError error) {
        // ...
    }
});

輸出:厚樸網站首頁的源代碼。

5.2 用POST方式請求網絡資源:

>new VolleyRequestUtil().RequestPOST(this, "http://ce.sysu.edu.cn/hope/", "hopePage", 
    new VolleyListenerInterface(this, VolleyListenerInterface.mListener, VolleyListenerInterface.mErrorListener) {
    // Volley請求成功時調用的函數
    @Override
    public void onMySuccess(String result) {
        Toast.makeText(MainActivity.this, result, Toast.LENGTH_LONG).show();
    }

    // Volley請求失敗時調用的函數
    @Override
    public void onMyError(VolleyError error) {
        // ...
    }
});

輸出:厚樸網站首頁的源代碼。

5.3 通過ImageRequest來顯示網絡圖片:

>// 參數分別為:請求圖片的地址、圖片的容器ImageView
ImageView imgView = (ImageView) findViewById(R.id.imgView);
        new ImageLoaderUtil().setImageRequest("http://7xinb0.com1.z0.glb.clouddn.com/skin/HopeRebuild/dist/images/logo/logo_40.png", imgView);

在布局文件中,定義ImageView:

><ImageView
        android:id="@+id/imgView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

5.4 通過ImageLoader來顯示網絡圖片:

>// 參數分別為:請求圖片的地址、圖片的容器ImageView、默認顯示的圖片ResourceID、請求失敗時顯示的圖片的ResourceID
new ImageLoaderUtil().setImageLoader("http://7xinb0.com1.z0.glb.clouddn.com/skin/HopeRebuild/dist/images/logo/logo_40.png", imgView, R.mipmap.default, R.mipmap.error);

在布局文件中,定義ImageView:

><ImageView
        android:id="@+id/imgView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

5.5 通過Volley的NetWorkImageView來顯示網絡圖片:

>// 參數分別為:請求圖片的地址、圖片的容器NetworkImageView、默認顯示的圖片ResourceID、請求失敗時顯示的圖片的ResourceID
NetworkImageView netWorkImageView = (NetworkImageView) findViewById(R.id.imgNetworkView);
        new ImageLoaderUtil().setNetWorkImageView("http://7xinb0.com1.z0.glb.clouddn.com/skin/HopeRebuild/dist/images/logo/logo_40.png", netWorkImageView, R.mipmap.default, R.mipmap.error);

在布局文件中,定義NetworkImageView:

><com.android.volley.toolbox.NetworkImageView  
               android:id="@+id/imgNetworkView"  
               android:layout_width="300dp"  
               android:layout_height="300dp"  
               android:layout_centerHorizontal="true"/>

六. 后記

該Volley的封裝中,暫未考慮到圖片和數據緩存。

有一些地方封裝得仍不夠抽象,有待完善。

非常歡迎讀者能提出修改建議,一起進步。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!