Volley框架
Volley是Google官方出的一套小而巧的異步請求庫,該框架封裝的擴展性很強,支持HttpClient、HttpUrlConnection,甚至支持OkHttp,而且Volley里面也封裝了ImageLoader,所以如果你愿意你甚至不需要使用圖片加載框架,不過這塊功能沒有一些專門的圖片加載框架強大,對于簡單的需求可以使用,對于稍復雜點的需求還是需要用到專門的圖片加載框架。
Volley也有缺陷,比如不支持post大數據,所以不適合上傳文件。不過Volley設計的初衷本身也就是為頻繁的、數據量小的網絡請求而生!
AndroidStudio中引入Volley
·引入volley.jar文件
·添加volley到gradle依賴(非官方)
·通過git下載volley,添加為項目module
Volley基本使用
這里以JsonRequest為例,首先我們需要創建一個RequestQueue requestQueue,然后構建一個自己所需要的XXRequest
req,之后通過requestQueue.add(req);將請求添加至請求隊列;
1.構建一個RequestQueue
RequestQueue
requestQueue=Volley.newRequestQueue(this);//這里的this指的是Context
2.創建一個Request(以JsonObjectRequest為例)
private final String
url="http:/xxxxx"http://所需url
JsonObjectRequest req=newJsonObjectRequest(url,null,new Response.Listener(){
@Override
public void onResponse(JsonObjectresponse){
//添加自己的響應邏輯,
}
},
new ResponseError.Listener(){
@Override
public void onResponseError(VollerErrorerror){
//錯誤處理
L.d("ErrorMessage:","Error is"+error);
}
})
3.將req添加到requestQueue
requestQueue.add(req);在構建JsonObjectRequest對象時,需要四個參數,其中第二個參數代表http方法,第三個和第四個分別是響應監聽和響應錯誤監聽,分別需要覆寫onResponse()和onResponseError()方法;RequestQueue將會執行請求,并將響應回調onResponse()方法,所以需要在onResponse()方法中實現自己的業務邏輯
4.?ImageRequest的用法
不同的地方就是,添加Request:
ImageRequest?imageRequest?=newImageRequest(
"url",
newResponse.Listener()?{
@Override
publicvoidonResponse(Bitmap?response)?{
imageView.setImageBitmap(response);
}
},?0,?0,?Config.RGB_565,newResponse.ErrorListener()?{
@Override
publicvoidonErrorResponse(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)。
5.ImageLoader的用法
ImageLoader也可以用于加載網絡上的圖片,并且它的內部也是使用ImageRequest來實現的,不過ImageLoader明顯要比ImageRequest更加高效,因為它不僅可以幫我們對圖片進行緩存,還可以過濾掉重復的鏈接,避免重復發送請求。
由于ImageLoader已經不是繼承自Request的了,所以它的用法也和我們之前學到的內容有所不同,總結起來大致可以分為以下四步:
1.創建一個RequestQueue對象。
2.創建一個ImageLoader對象。
3.獲取一個ImageListener對象。
4.調用ImageLoader的get()方法加載網絡上的圖片。
首先第一步的創建RequestQueue對象這里就不再重復介紹了,那么就從第二步開始,新建一個ImageLoader對象,代碼如下所示:
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控件,第二個參數指定加載圖片的過程中顯示的圖片,第三個參數指定加載圖片失敗的情況下顯示的圖片。
最后,調用ImageLoader的get()方法來加載圖片,代碼如下所示:
imageLoader.get("url",?listener);
get()方法接收兩個參數,第一個參數就是圖片的URL地址,第二個參數則是剛剛獲取到的ImageListener對象。當然,如果你想對圖片的大小進行限制,也可以使用get()方法的重載,指定圖片允許的最大寬度和高度,如下所示:
imageLoader.get("url",?listener,?200,?200);
雖然現在我們已經掌握了ImageLoader的用法,但是剛才介紹的ImageLoader的優點卻還沒有使用到。為什么呢?因為這里創建的ImageCache對象是一個空的實現,完全沒能起到圖片緩存的作用。其實寫一個ImageCache也非常簡單,但是如果想要寫一個性能非常好的ImageCache,最好就要借助Android提供的LruCache功能了,這里就不做介紹了,有興趣的可以看一下LruCache。
6.NetworkImageView的用法
除了以上兩種方式之外,Volley還提供了第三種方式來加載網絡圖片,即使用NetworkImageView。不同于以上兩種方式,NetworkImageView是一個自定義控制,它是繼承自ImageView的,具備ImageView控件的所有功能,并且在原生的基礎之上加入了加載網絡圖片的功能。NetworkImageView控件的用法要比前兩種方式更加簡單,大致可以分為以下五步:
1.創建一個RequestQueue對象。
2.創建一個ImageLoader對象。
3.在布局文件中添加一個NetworkImageView控件。
4.在代碼中獲取該控件的實例。
5.設置要加載的圖片地址。
其中,第一第二步和ImageLoader的用法是完全一樣的,因此這里我們就從第三步開始學習了。首先修改布局文件中的代碼,在里面加入NetworkImageView控件,如下所示:
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"?>
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send?Request"?/>
android:id="@+id/network_image_view"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal"
/>
接著在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("url",??imageLoader);
其中,setImageUrl()方法接收兩個參數,第一個參數用于指定圖片的URL地址,第二個參數則是前面創建好的ImageLoader對象。
定制自己的Request
1.自定義XMLRequest
自定義一個XMLRequest,用于請求一條XML格式的數據。那么該從哪里開始入手呢?額,好像是有些無從下手。遇到這種情況,我們應該去參考一下Volley的源碼,看一看StringRequest是怎么實現的,然后就可以模仿著寫出XMLRequest了。首先看下StringRequest的源碼,如下所示:
/**
*?A?canned?request?for?retrieving?the?response?body?at?a?given?URL?as?a?String.
*/
public?class?StringRequest?extends?Request?{
private?final?Listener?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?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?listener,?ErrorListener?errorListener)?{
this(Method.GET,?url,?listener,?errorListener);
}
@Override
protected?void?deliverResponse(String?response)?{
mListener.onResponse(response);
}
@Override
protected?Response?parseNetworkResponse(NetworkResponse?response)?{
String?parsed;
try?{
parsed?=?new?String(response.data,?HttpHeaderParser.parseCharset(response.headers));
}?catch?(UnsupportedEncodingException?e)?{
parsed?=?new?String(response.data);
}
return?Response.success(parsed,?HttpHeaderParser.parseCacheHeaders(response));
}
}
可以看到,首先StringRequest是繼承自Request類的,Request可以指定一個泛型類,這里指定的當然就是String了,接下來StringRequest中提供了兩個有參的構造函數,參數包括請求類型,請求地址,以及響應回調等,需要注意的是,在構造函數中一定要調用super()方法將這幾個參數傳給父類,因為HTTP的請求和響應都是在父類中自動處理的。
另外,由于Request類中的deliverResponse()和parseNetworkResponse()是兩個抽象方法,因此StringRequest中需要對這兩個方法進行實現。deliverResponse()方法中的實現很簡單,僅僅是調用了mListener中的onResponse()方法,并將response內容傳入即可,這樣就可以將服務器響應的數據進行回調了。parseNetworkResponse()方法中則應該對服務器響應的數據進行解析,其中數據是以字節的形式存放在NetworkResponse的data變量中的,這里將數據取出然后組裝成一個String,并傳入Response的success()方法中即可。
了解了StringRequest的實現原理,下面我們就可以動手來嘗試實現一下XMLRequest了,代碼如下所示:
public?class?XMLRequest?extends?Request?{
private?final?Listener?mListener;
public?XMLRequest(int?method,?String?url,?Listener?listener,
ErrorListener?errorListener)?{
super(method,?url,?errorListener);
mListener?=?listener;
}
public?XMLRequest(String?url,?Listener?listener,?ErrorListener?errorListener)?{
this(Method.GET,?url,?listener,?errorListener);
}
@Override
protected?Response?parseNetworkResponse(NetworkResponse?response)?{
try?{
String?xmlString?=?new?String(response.data,
HttpHeaderParser.parseCharset(response.headers));
XmlPullParserFactory?factory?=?XmlPullParserFactory.newInstance();
XmlPullParser?xmlPullParser?=?factory.newPullParser();
xmlPullParser.setInput(new?StringReader(xmlString));
return?Response.success(xmlPullParser,?HttpHeaderParser.parseCacheHeaders(response));
}?catch?(UnsupportedEncodingException?e)?{
return?Response.error(new?ParseError(e));
}?catch?(XmlPullParserException?e)?{
return?Response.error(new?ParseError(e));
}
}
@Override
protected?void?deliverResponse(XmlPullParser?response)?{
mListener.onResponse(response);
}
}
可以看到,基本都是仿照StringRequest寫下來的,XMLRequest也是繼承自Request類的,只不過這里指定的泛型類是XmlPullParser,說明我們準備使用Pull解析(XML解析方式dom、sax、pull)的方式來解析XML。在parseNetworkResponse()方法中,先是將服務器響應的數據解析成一個字符串,然后設置到XmlPullParser對象中,在deliverResponse()方法中則是將XmlPullParser對象進行回調。
2.自定義GsonRequest
JsonRequest的數據解析是利用Android本身自帶的JSONObject和JSONArray來實現的,配合使用JSONObject和JSONArray就可以解析出任意格式的JSON數據。不過也許你會覺得使用JSONObject還是太麻煩了,還有很多方法可以讓JSON數據解析變得更加簡單,比如說GSON。遺憾的是,Volley中默認并不支持使用自家的GSON來解析數據,不過沒有關系,通過上面的學習,相信你已經知道了自定義一個Request是多么的簡單,那么下面我們就來舉一反三一下,自定義一個GsonRequest。
首先我們需要把gson的jar包添加到項目當中,jar包的下載地址是:https://code.google.com/p/google-gson/downloads/list。
接著定義一個GsonRequest繼承自Request,代碼如下所示:
public?class?GsonRequest?extends?Request?{
private?final?Listener?mListener;
private?Gson?mGson;
private?Class?mClass;
public?GsonRequest(int?method,?String?url,?Class?clazz,?Listener?listener,
ErrorListener?errorListener)?{
super(method,?url,?errorListener);
mGson?=?new?Gson();
mClass?=?clazz;
mListener?=?listener;
}
public?GsonRequest(String?url,?Class?clazz,?Listener?listener,
ErrorListener?errorListener)?{
this(Method.GET,?url,?clazz,?listener,?errorListener);
}
@Override
protected?Response?parseNetworkResponse(NetworkResponse?response)?{
try?{
String?jsonString?=?new?String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return?Response.success(mGson.fromJson(jsonString,?mClass),
HttpHeaderParser.parseCacheHeaders(response));
}?catch?(UnsupportedEncodingException?e)?{
return?Response.error(new?ParseError(e));
}
}
@Override
protected?void?deliverResponse(T?response)?{
mListener.onResponse(response);
}
}
可以看到,GsonRequest是繼承自Request類的,并且同樣提供了兩個構造函數。在parseNetworkResponse()方法中,先是將服務器響應的數據解析出來,然后通過調用Gson的fromJson方法將數據組裝成對象。在deliverResponse方法中仍然是將最終的數據進行回調