Volley框架的功能和實現機制

參考:https://blog.csdn.net/guolin_blog/article/details/17482095

 

背景:Android系統中主要提供了兩種方式來進行HTTP通信,HttpURLConnection和HttpClient,但是用法稍微有些複雜的,如果不進行適當封裝的話,很容易就會寫出不少重複代碼。一些Android網絡通信框架也就應運而生,比如說AsyncHttpClient(它把HTTP所有的通信細節全部封裝在了內部,我們只需要簡單調用幾行代碼就可以完成通信操作了)和Universal-Image-Loader(它使得在界面上顯示網絡圖片的操作變得極度簡單,開發者不用關心如何從網絡上獲取圖片,也不用關心開啓線程、回收圖片資源等細節)

2013年Google I/O大會上推出的Volley,把AsyncHttpClient和Universal-Image-Loader的優點集於了一身。

 

適用場景:數據量不大,但網絡通信頻繁的數據請求

 

功能一:

StringRequest實現HTTP發送與響應

1. 創建一個RequestQueue對象。

//獲取到一個RequestQueue對象
RequestQueue mQueue = Volley.newRequestQueue(context);

注意這裏拿到的RequestQueue是一個請求隊列對象,它可以緩存所有的HTTP請求,然後按照一定的算法併發地發出這些請求。RequestQueue內部的設計就是非常合適高併發的,因此我們不必爲每一次HTTP請求都創建一個RequestQueue對象,這是非常浪費資源的,基本上在每一個需要和網絡交互的Activity中創建一個RequestQueue對象就足夠了。
 

2. 創建一個StringRequest對象。

StringRequest stringRequest = new StringRequest("http://www.baidu.com",
						new Response.Listener<String>() {
							@Override
							public void onResponse(String response) {
								Log.d("TAG", response);
							}
						}, new Response.ErrorListener() {
							@Override
							public void onErrorResponse(VolleyError error) {
								Log.e("TAG", error.getMessage(), error);
							}
						});

這裏new出了一個StringRequest對象,StringRequest的構造函數需要傳入三個參數,第一個參數就是目標服務器的URL地址,第二個參數是服務器響應成功的回調,第三個參數是服務器響應失敗的回調。其中,目標服務器地址我們填寫的是百度的首頁,然後在響應成功的回調裏打印出服務器返回的內容,在響應失敗的回調裏打印出失敗的詳細信息。
 

3. 將StringRequest對象添加到RequestQueue裏面。

mQueue.add(stringRequest);

 

但是HTTP的請求類型通常有兩種,GET和POST,以上爲GET請求。

以下爲POST請求:

StringRequest中還提供了另外一種四個參數的構造函數,其中第一個參數就是指定請求類型的,使用如下方式進行指定:

StringRequest stringRequest = new StringRequest(Method.POST, url,  listener, errorListener);

 

要提交給服務器的參數又該怎麼設置呢?很遺憾,StringRequest中並沒有提供設置POST參數的方法,但是當發出POST請求的時候,Volley會嘗試調用StringRequest的父類——Request中的getParams()方法來獲取POST參數,那麼解決方法自然也就有了,我們只需要在StringRequest的匿名類中重寫getParams()方法,在這裏設置POST參數就可以了,代碼如下所示:
 

StringRequest stringRequest = new StringRequest(Method.POST, url,  listener, errorListener) {
	@Override
	protected Map<String, String> getParams() throws AuthFailureError {
		Map<String, String> map = new HashMap<String, String>();
		map.put("params1", "value1");
		map.put("params2", "value2");
		return map;
	}
};

 

附:JsonRequest的用法

至於它們的用法也基本上沒有什麼特殊之處,先new出一個JsonObjectRequest對象:

JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("http://m.weather.com.cn/data/101010100.html", null,
		new Response.Listener<JSONObject>() {
			@Override
			public void onResponse(JSONObject response) {
				Log.d("TAG", response.toString());
			}
		}, new Response.ErrorListener() {
			@Override
			public void onErrorResponse(VolleyError error) {
				Log.e("TAG", error.getMessage(), error);
			}
		});

這裏我們填寫的URL地址是http://m.weather.com.cn/data/101010100.html,這是中國天氣網提供的一個查詢天氣信息的接口,響應的數據就是以JSON格式返回的,然後我們在onResponse()方法中將返回的數據打印出來。

 

最後再將這個JsonObjectRequest對象添加到RequestQueue裏就可以了:

mQueue.add(jsonObjectRequest);

onResponse()方法中攜帶的參數也正是一個JSONObject對象,之後只需要從JSONObject對象取出我們想要得到的那部分數據就可以了。

 

功能二:

加載網絡圖片

參考:https://blog.csdn.net/guolin_blog/article/details/17482165

 

Universal-Image-Loader具備非常強大的加載網絡圖片的功能,而使用Volley,我們也可以實現基本類似的效果,並且在性能上也豪不遜色於Universal-Image-Loader。

1、ImageRequest:

//首先需要獲取到一個RequestQueue對象
RequestQueue mQueue = Volley.newRequestQueue(context);

//new出一個ImageRequest對象
ImageRequest imageRequest = new ImageRequest(
		"http://developer.android.com/images/home/aw_dac.png",
		new Response.Listener<Bitmap>() {
			@Override
			public void onResponse(Bitmap response) {
				imageView.setImageBitmap(response);
			}
		}, 0, 0, Config.RGB_565, new Response.ErrorListener() {
			@Override
			public void onErrorResponse(VolleyError error) {
				imageView.setImageResource(R.drawable.default_image);
			}
		});

ImageRequest的構造函數接收六個參數,第一個參數就是圖片的URL地址,這個沒什麼需要解釋的。第二個參數是圖片請求成功的回調,這裏我們把返回的Bitmap參數設置到ImageView中。第三第四個參數分別用於指定允許圖片最大的寬度和高度,如果指定的網絡圖片的寬度或高度大於這裏的最大值,則會對圖片進行壓縮,指定成0的話就表示不管圖片有多大,都不會進行壓縮。第五個參數用於指定圖片的顏色屬性,Bitmap.Config下的幾個常量都可以在這裏使用,其中ARGB_8888可以展示最好的顏色屬性,每個圖片像素佔據4個字節的大小,而RGB_565則表示每個圖片像素佔據2個字節大小。第六個參數是圖片請求失敗的回調,這裏我們當請求失敗時在ImageView中顯示一張默認圖片。
 

最後將這個ImageRequest對象添加到RequestQueue裏:

mQueue.add(imageRequest);

 

2、ImageLoader:

ImageLoader也可以用於加載網絡上的圖片,並且它的內部也是使用ImageRequest來實現的,不過ImageLoader明顯要比ImageRequest更加高效,因爲它不僅可以幫我們對圖片進行緩存,還可以過濾掉重複的鏈接,避免重複發送請求。

 

由於ImageLoader已經不是繼承自Request的了,所以它的用法也和我們之前學到的內容有所不同,總結起來大致可以分爲以下四步:

1. 創建一個RequestQueue對象。

2. 創建一個ImageLoader對象。

3. 獲取一個ImageListener對象。

4. 調用ImageLoader的get()方法加載網絡上的圖片。

 

RequestQueue mQueue = Volley.newRequestQueue(context);

ImageLoader imageLoader = new ImageLoader(mQueue, new ImageCache() {
	@Override
	public void putBitmap(String url, Bitmap bitmap) {
	}
 
	@Override
	public Bitmap getBitmap(String url) {
		return null;
	}
});

ImageLoader的構造函數接收兩個參數,第一個參數就是RequestQueue對象,第二個參數是一個ImageCache對象,這裏我們先new出一個空的ImageCache的實現即可。

 

接下來需要獲取一個ImageListener對象,代碼如下所示:

ImageListener listener = ImageLoader.getImageListener(imageView,
		R.drawable.default_image, R.drawable.failed_image);

我們通過調用ImageLoader的getImageListener()方法能夠獲取到一個ImageListener對象,getImageListener()方法接收三個參數,第一個參數指定用於顯示圖片的ImageView控件,第二個參數指定加載圖片的過程中顯示的圖片,第三個參數指定加載圖片失敗的情況下顯示的圖片。

 

3、NetworkImageView:

不同於以上兩種方式,NetworkImageView是一個自定義控制,它是繼承自ImageView的,具備ImageView控件的所有功能,並且在原生的基礎之上加入了加載網絡圖片的功能。NetworkImageView控件的用法要比前兩種方式更加簡單,大致可以分爲以下五步:

1. 創建一個RequestQueue對象。

2. 創建一個ImageLoader對象。

3. 在佈局文件中添加一個NetworkImageView控件。
4. 在代碼中獲取該控件的實例。

5. 設置要加載的圖片地址。
 

第一第二步和ImageLoader的用法是完全一樣的,因此這裏我們就從第三步開始學習了。首先修改佈局文件中的代碼,在裏面加入NetworkImageView控件,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
 
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send Request" />
    
    <com.android.volley.toolbox.NetworkImageView 
        android:id="@+id/network_image_view"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_gravity="center_horizontal"
        />
 
</LinearLayout>

 

接着在Activity獲取到這個控件的實例,這就非常簡單了,代碼如下所示:

networkImageView = (NetworkImageView) findViewById(R.id.network_image_view);

 

得到了NetworkImageView控件的實例之後,我們可以調用它的setDefaultImageResId()方法、setErrorImageResId()方法和setImageUrl()方法來分別設置加載中顯示的圖片,加載失敗時顯示的圖片,以及目標圖片的URL地址,如下所示:
 

networkImageView.setDefaultImageResId(R.drawable.default_image);
networkImageView.setErrorImageResId(R.drawable.failed_image);
networkImageView.setImageUrl("https://img-my.csdn.net/uploads/201404/13/1397393290_5765.jpeg",
				imageLoader);

其中,setImageUrl()方法接收兩個參數,第一個參數用於指定圖片的URL地址,第二個參數則是前面創建好的ImageLoader對象。

 

功能三:

自定義XMLRequest

參考:https://blog.csdn.net/guolin_blog/article/details/17612763

 

 

實現機制(原理):

參考:https://blog.csdn.net/guolin_blog/article/details/17656437

我們在主線程中調用RequestQueue的add()方法來添加一條網絡請求,這條請求會先被加入到緩存隊列當中,如果發現可以找到相應的緩存結果就直接讀取緩存並解析,然後回調給主線程。如果在緩存中沒有找到結果,則將這條請求加入到網絡請求隊列中,然後處理髮送HTTP請求,解析響應結果,寫入緩存,並回調主線程。
 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章