Android:Volley的使用及其工具類的封裝
一. 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工作原理圖如下:
使用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的封裝中,暫未考慮到圖片和數據緩存。
有一些地方封裝得仍不夠抽象,有待完善。
非常歡迎讀者能提出修改建議,一起進步。