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的封裝中,暫未考慮到圖片和數據緩存。
有一些地方封裝得仍不夠抽象,有待完善。
非常歡迎讀者能提出修改建議,一起進步。