引言:對于網(wǎng)絡(luò)請求這塊來說最早接觸是
AsyncHttpClient后來又簡單接觸了xUtils再后來就是OkHttp了,官方的Volley只是聽說過,并沒有真正使用過。時(shí)間:2016年12月03日00:18:35
作者:JustDo23
01. 簡介
在慕課網(wǎng)上找了相關(guān)視頻Android-Volley詳解
Volley是 Google 在2013年推出的 Android 平臺(tái)的網(wǎng)絡(luò)通信庫。Volley特點(diǎn),快捷,簡單,網(wǎng)絡(luò)圖像,高效異步處理請求排序,緩存,多級(jí)別取消,和 Activity 生命周期聯(lián)動(dòng);缺點(diǎn)是不適合進(jìn)行文件的上傳下載。
Volley的請求同樣是包含有get和post請求;同時(shí)根據(jù)返回結(jié)果的不同可以挑選使用StringRequest或JsonObjectRequest或JsonArrayRequest;請求回調(diào)有Success或Error等回調(diào);全局建立一個(gè)請求隊(duì)列,方便網(wǎng)絡(luò)請求的添加和取消;使用tag標(biāo)簽方便查找請求,并管理請求的取消,和 Activity 進(jìn)行聯(lián)動(dòng)使用。
建議:在這里強(qiáng)調(diào)一下,不論使用的是什么網(wǎng)絡(luò)請求框,都應(yīng)該自己進(jìn)行一下二次封裝,方便同一管理。
02. 入門代碼
在Gradle文件中導(dǎo)入依賴
compile 'com.android.volley:volley:1.0.0'
新建Application并實(shí)例化請求隊(duì)列
public class JustApplication extends Application {
private static RequestQueue requestQueue;// 全局的請求隊(duì)列
@Override
public void onCreate() {
super.onCreate();
requestQueue = Volley.newRequestQueue(this);// 實(shí)例化請求隊(duì)列
}
public static RequestQueue getRequestQueue() {
return requestQueue;
}
}
在 Activity 中進(jìn)行網(wǎng)絡(luò)請求
private void doStringGet() {
String url = "https://www.baidu.com";// 參數(shù):[請求方式][請求鏈接][成功回調(diào)][失敗回調(diào)]
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
LogUtil.e(response);// 這個(gè)是成功的回調(diào)
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
LogUtil.e(error.toString());// 這個(gè)是失敗的回調(diào)
}
});
stringRequest.setTag("doVolleyGet");// 設(shè)置標(biāo)簽
JustApplication.getRequestQueue().add(stringRequest);// 將請求添加進(jìn)隊(duì)列
}
使用POST方式進(jìn)行網(wǎng)絡(luò)請求,和GET方式不同的是需要將參數(shù)進(jìn)行封裝
private void doStringPost() {
String url = "https://www.baidu.com";// 參數(shù):[請求方式][請求鏈接][成功回調(diào)][失敗回調(diào)]
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, null, null) {// 重寫父類的方法,返回網(wǎng)絡(luò)請求的參數(shù)
@Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("phone", "15812345678");
params.put("key", "abcdefghigklmn");
return params;
}
};
stringRequest.setTag("doStringPost");// 設(shè)置標(biāo)簽
JustApplication.getRequestQueue().add(stringRequest);// 將請求添加進(jìn)隊(duì)列
}
另外使用JsonObjectRequest進(jìn)行網(wǎng)絡(luò)請求和StringRequest也有些區(qū)別,就是不用重寫返回參數(shù),而是將一個(gè)JsonObject對象的參數(shù)直接進(jìn)行傳遞。
private void doJsonPost() {
String url = "https://www.baidu.com";
Map<String, String> params = new HashMap<>();
params.put("phone", "15812345678");
params.put("key", "abcdefghigklmn");
JSONObject jsonObject = new JSONObject(params);// 將 Map 轉(zhuǎn)為 JsonObject 的參數(shù)
// 參數(shù):[請求方式][請求鏈接][請求參數(shù)][成功回調(diào)][失敗回調(diào)]
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, url, jsonObject, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
LogUtil.e(response.toString());// 這個(gè)是成功的回調(diào)
}
}, null);
jsonObjectRequest.setTag("doJsonPost");// 設(shè)置標(biāo)簽
JustApplication.getRequestQueue().add(jsonObjectRequest);// 將請求添加進(jìn)隊(duì)列
}
在現(xiàn)有代碼的基礎(chǔ)上,給界面添加一個(gè) TextView 并在 Volley 網(wǎng)絡(luò)請求的回調(diào)中直接將返回的數(shù)據(jù)設(shè)置給 TextView ,測試發(fā)現(xiàn)回調(diào)可以直接操作UI。
03. 加載網(wǎng)絡(luò)圖片
方式一:直接請求圖片 URL 并將圖片進(jìn)行顯示
public void getNetImage() {
String imageUrl = "http://img4.duitang.com/uploads/item/201509/30/20150930002351_3vHWx.thumb.700_0.jpeg";
// 參數(shù):[圖片Url][成功回調(diào)][圖片最大寬度][圖片最大高度][填充方式][位圖配置][失敗回調(diào)]
ImageRequest imageRequest = new ImageRequest(imageUrl, new Response.Listener<Bitmap>() {
@Override
public void onResponse(Bitmap response) {
iv_show.setImageBitmap(response);// 請求成功返回 Bitmap 方便使用
}// [圖片最大寬度][圖片最大高度]給0表示原圖顯示,否則會(huì)進(jìn)行壓縮
}, 0, 0, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.RGB_565, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
iv_show.setImageResource(R.mipmap.ic_launcher);// 請求失敗的回調(diào)
}
});
imageRequest.setTag("getNetImage");// 設(shè)置標(biāo)簽
JustApplication.getRequestQueue().add(imageRequest);// 添加進(jìn)隊(duì)列
}
方式二:使用 ImageLoader 配合 ImageCache 及 ImageListener 進(jìn)行圖片顯示
public void getNetImage() {
String imageUrl = "http://img4.duitang.com/uploads/item/201509/30/20150930002351_3vHWx.thumb.700_0.jpeg";
// [獲取一個(gè) ImageLoader 對象] 參數(shù):[請求隊(duì)列][圖片緩存對象]
ImageLoader imageLoader = new ImageLoader(JustApplication.getRequestQueue(), new BitmapCache());
// [獲取一個(gè) ImageListener 對象] 參數(shù):[ ImageView ][默認(rèn)顯示圖片][加載失敗顯示圖片]
ImageLoader.ImageListener imageListener = ImageLoader.getImageListener(iv_show, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
// [使用 ImageLoader 加載圖片] 參數(shù):[圖片Url][圖片加載監(jiān)聽][圖片最大寬度][圖片最大高度][填充方式]
imageLoader.get(imageUrl, imageListener, 0, 0, ImageView.ScaleType.CENTER_CROP);
}
進(jìn)行圖片緩存的類
/**
* 圖片緩存
*
* @author JustDo23
*/
public class BitmapCache implements ImageLoader.ImageCache {
private LruCache<String, Bitmap> cache;// 緩存圖片
private int maxSize = 10 * 1024 * 1024;// 最大10MB
/**
* 構(gòu)造方法中實(shí)例化
*/
public BitmapCache() {
cache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
}
/**
* 獲取圖片
*
* @param url 圖片 URL
* @return 圖片 Bitmap
*/
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
/**
* 緩存圖片
*
* @param url 圖片 URL
* @return 圖片 Bitmap
*/
@Override
public void putBitmap(String url, Bitmap bitmap) {
cache.put(url, bitmap);
}
}
方式二:使用 Volley 內(nèi)部封裝的顯示網(wǎng)絡(luò)圖片控件 NetworkImageView
niv_show = (NetworkImageView) findViewById(R.id.niv_show);
public void getNetImage() {
String imageUrl = "http://img4.duitang.com/uploads/item/201509/30/20150930002351_3vHWx.thumb.700_0.jpeg";
// [獲取一個(gè) ImageLoader 對象] 參數(shù):[請求隊(duì)列][圖片緩存對象]
ImageLoader imageLoader = new ImageLoader(JustApplication.getRequestQueue(), new BitmapCache());
// [設(shè)置默認(rèn)顯示圖片]
niv_show.setDefaultImageResId(R.mipmap.ic_launcher);
// [設(shè)置加載失敗顯示圖片]
niv_show.setErrorImageResId(R.mipmap.ic_launcher);
// [設(shè)置 URL 和 ImageLoader]
niv_show.setImageUrl(imageUrl, imageLoader);
}
04. 自定義 Request
Android Volley完全解析(三),定制自己的Request
當(dāng) Volley 本身提供的請求不夠用的時(shí)候,可以參考 Volley 中請求的實(shí)現(xiàn)方式來進(jìn)行自定義。其中Request<T>帶泛型的請求基類。看下StringRequest的源碼
/**
* A canned request for retrieving the response body at a given URL as a String.
*/
public class StringRequest extends Request<String> {
private final Listener<String> 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<String> 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<String> listener, ErrorListener errorListener) {
this(Method.GET, url, listener, errorListener);
}
@Override
protected void deliverResponse(String response) {
mListener.onResponse(response);
}
@Override
protected Response<String> 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));
}
}
再此基礎(chǔ)上,編寫自定義的 Request
/**
* 帶有 XML 解析的網(wǎng)絡(luò)請求
*
* @author JustDo23
*/
public class XMLRequest extends Request<XmlPullParser> {
private final Response.Listener<XmlPullParser> mListener;// 網(wǎng)絡(luò)請求成功的回調(diào)
/**
* [必須有一個(gè)][構(gòu)造方法]
*
* @param method 請求方式
* @param url 請求的網(wǎng)絡(luò)地址
* @param listener 成功的回調(diào)
* @param errorListener 失敗的回調(diào)
*/
public XMLRequest(int method, String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
/**
* 默認(rèn)的 GET 請求
*/
public XMLRequest(String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) {
this(Method.GET, url, listener, errorListener);
}
/**
* [必須重寫][網(wǎng)絡(luò)請求返回?cái)?shù)據(jù)]
*
* @param response 網(wǎng)絡(luò)請求結(jié)果
* @return 處理之后的數(shù)據(jù)
*/
@Override
protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {
try {// 先獲取網(wǎng)絡(luò)返回是字符串再將字符串轉(zhuǎn)成流傳遞給解析器最后將解析器返回
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));
}
}
/**
* [必須重寫][將parseNetworkResponse方法返回的數(shù)據(jù)返回給主線程]
*
* @param response
*/
@Override
protected void deliverResponse(XmlPullParser response) {
mListener.onResponse(response);
}
}
再利用 Gson 進(jìn)行封裝
/**
* 帶有 Gson 解析的網(wǎng)絡(luò)請求
*
* @author JustDo23
*/
public class GsonRequest<T> extends Request<T> {
private final Response.Listener<T> mListener;// 網(wǎng)絡(luò)請求成功的回調(diào)
private Gson mGson;// Gson 對象
private Class<T> mClass;// 解析后 JavaBean
public GsonRequest(int method, String url, Class<T> clazz, Response.Listener<T> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
mClass = clazz;
mListener = listener;
}
public GsonRequest(String url, Class<T> clazz, Response.Listener<T> listener, Response.ErrorListener errorListener) {
this(Method.GET, url, clazz, listener, errorListener);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {// 先獲取網(wǎng)絡(luò)請求返回的Json字符串,再利用Gson將字符串轉(zhuǎn)成對象
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);
}
}
05. 再度深入
Android Volley完全解析(四),帶你從源碼的角度理解Volley
全局維護(hù)一個(gè)隊(duì)列,根據(jù)手機(jī)版本的不同使用不用的HttpStack當(dāng)然也可以擴(kuò)展到使用OKHttp,首次初始化5個(gè)網(wǎng)絡(luò)請求線程,先初始化一個(gè)帶緩存的網(wǎng)絡(luò)請求線程,再初始化四個(gè)不帶緩存的網(wǎng)絡(luò)請求線程。默認(rèn)情況下,每條網(wǎng)絡(luò)請求都是可以進(jìn)行緩存的。獲取到緩存之后,還會(huì)判斷緩存是否已經(jīng)過期,過期則重新進(jìn)行網(wǎng)絡(luò)請求否則直接使用緩存。
06. Https
Android 網(wǎng)絡(luò)--我是怎么做的: Volley+OkHttp+Https
利用 Volley 實(shí)現(xiàn) Https 在網(wǎng)上大概就幾種方式:直接信任所有,跳過驗(yàn)證,拓展到 OKHttp 添加證書等等。這篇文章是在網(wǎng)絡(luò)上找的比較好的一篇。
使用自簽名的證書進(jìn)行操作,就會(huì)遇到這些比較復(fù)雜麻煩的問題,例如訪問12306網(wǎng)站。一般只要是使用CA證書認(rèn)證的網(wǎng)站,默認(rèn)都是信任的,直接就能進(jìn)行訪問的,比如https:www.baidu.com在 Volley 中同樣可以直接訪問不要考慮認(rèn)證的問題。由于iOS年底提交項(xiàng)目必須使用https所以接口面臨證書之類的問題,寶寶真是好害怕,一切都準(zhǔn)備就緒后,不料買了個(gè)CA 證書,結(jié)果問題簡單化。
證書操作
01. 將 CER 證書轉(zhuǎn)成 BKS
參考:http://blog.csdn.net/u010314594/article/details/50765534
工具: [ JCE Provider ] bcprov-jdk15on-155.jar http://www.bouncycastle.org/latest_releases.html 在網(wǎng)站下載到最新版。
命令:下載之后需要使用命令行進(jìn)行操作,這個(gè)命令比較多,而且不能有回車。
keytool -importcert -v -trustcacerts -alias 位置1
-file 位置2
-keystore 位置3 -storetype BKS
-providerclass org.bouncycastle.jce.provider.BouncyCastleProvider
-providerpath 位置4
-storepass 位置5
解釋:
位置1:是個(gè)隨便取的別名,供keytool方便管理
位置2:cer或crt證書的全地址
位置3:生成后bks文件的位置,建議寫全地址
位置4:上面下載JCE Provider包的位置
位置5:生成后證書的密碼,自己設(shè)置,需要在項(xiàng)目中使用,用于確保KeyStore文件本身安全
命令執(zhí)行之后,如果失敗會(huì)有報(bào)錯(cuò)提示,使用最新版本基本沒有問題。命令執(zhí)行成功,最后會(huì)有中文[是|否]的選擇,輸入[是]即可完成全部過程。命名要符號(hào) Java 命名規(guī)范。
// 個(gè)人操作命令
keytool -importcert -v -trustcacerts -alias test12306 -file /Users/just/Desktop/test12306/srca.cer -keystore /Users/just/Desktop/test12306/test12306.bks -storetype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath /Users/just/Desktop/test12306/bcprov-jdk15on-155.jar -storepass test12306
02. 提取 CER 證書字符串
命令:
keytool -printcert -rfc -file xxx.cer
命令行操作,證書文件路徑可全路徑,可在證書所在目錄執(zhí)行。
Demo 地址