構(gòu)造RequestQueue實例
如果我們的應(yīng)用需要經(jīng)常使用網(wǎng)絡(luò),那么創(chuàng)建一個單例的RequestQueue會更加高效。
public class MyVolleyHelper {
private static MyVolleyHelper mInstance;
private RequestQueue mRequestQueue;
private static Context mContext;
private MyVolleyHelper(Context context) {
mContext = context;
}
public static synchronized MyVolleyHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new MyVolleyHelper(context);
}
return mInstance;
}
public RequestQueue getRequestQueue() {
if (mRequestQueue == null) {
// getApplicationContext() 是關(guān)鍵, 它避免了你
//傳遞進Activity或BroadcastReceiver導(dǎo)致的內(nèi)存泄漏
mRequestQueue = Volley.newRequestQueue(mContext.getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req) {
getRequestQueue().add(req);
}
}
Volley get請求
- JsonObjectRequest 用來接收和發(fā)送JsonObject類型的數(shù)據(jù)
- JsonArrayRequest 用來接收和發(fā)送JsonArray類型的數(shù)據(jù)
- StringRequest 用來接收和發(fā)送響應(yīng)主體為String的數(shù)據(jù)
下面以JsonArrayRequest為例,volley的onResponse方法是在主線程上,所以可以進行ui的更新,如果有耗時的操作,需要放到thread中操作。
private void getVolleyData() {
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET,
uri,null,
new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
/// 在UI thread上
///refresh ui
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "error = "+error);
}
});
///設(shè)置tag,方便取消對應(yīng)tag的request
jsonArrayRequest.setTag(requestTAG);
MyVolleyHelper.getInstance(getApplicationContext()).addToRequestQueue(jsonArrayRequest);
}
返回錯誤類型有以下幾種:
- AuthFailureError:如果在做一個HTTP的身份驗證,可能會發(fā)生這個錯誤。
- NetworkError:Socket關(guān)閉,服務(wù)器宕機,DNS錯誤都會產(chǎn)生這個錯誤。
- NoConnectionError:和NetworkError類似,這個是客戶端沒有網(wǎng)絡(luò)連接。
- ParseError:在使用JsonObjectRequest或JsonArrayRequest時,如果接收到的JSON是畸形,會產(chǎn)生異常。
- SERVERERROR:服務(wù)器的響應(yīng)的一個錯誤,最有可能的4xx或5xx HTTP狀態(tài)代碼。
- TimeoutError:Socket超時,服務(wù)器太忙或網(wǎng)絡(luò)延遲會產(chǎn)生這個異常。默認情況下,Volley的超時時間為2.5秒。如果得到這個錯誤可以使用RetryPolicy。
另外還有ImageRequest和ImageLoader的使用。
- 通過Volley請求,在普通ImageView上顯示圖片。
- 通過Volley請求,在普通NetworkImageView上顯示圖片。
private void imageLoaderRequest() {
//實例化ImageLoader
ImageLoader imageLoader = new ImageLoader(MyVolleyHelper.getInstance(getApplicationContext()).getRequestQueue(),
new BitmapCache());
boolean debugNetImage = true;//Test code
if (debugNetImage) {
networkImageView.setDefaultImageResId(R.mipmap.ic_launcher);
networkImageView.setErrorImageResId(R.mipmap.ic_launcher);
networkImageView.setImageUrl(URI, imageLoader);
}else {
//設(shè)置監(jiān)聽器
ImageLoader.ImageListener listener =
ImageLoader.getImageListener(imageView, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
//3.獲取圖片
imageLoader.get(URI, listener);
}
}
BitmapCache 主要用來設(shè)置圖片緩存大小
public class BitmapCache implements ImageLoader.ImageCache {
private LruCache<String, Bitmap> mCache;
public BitmapCache() {
int maxSize = 10 * 1024 * 1024;
///緩存圖片的大小設(shè)置為10M
mCache = new LruCache<String, Bitmap>(maxSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight();
}
};
}
@Override
public Bitmap getBitmap(String url) {
return mCache.get(url);
}
@Override
public void putBitmap(String url, Bitmap bitmap) {
mCache.put(url, bitmap);
}
}
Vollet post請求
這個部分是我最想要說的,因為使用post請求的時候參數(shù)始終無法獲取到正常的數(shù)據(jù),用okhttp傳遞相同的參數(shù)是可以獲取到返回的數(shù)據(jù)的,而volley怎么都不可以。所以查看了網(wǎng)上的一些介紹,在此特意記錄一下。
以前是我測試的方法嘗試:
服務(wù)器返回的是JsonObject,所以我們要用JsonObjectRequest來請求。
private void postDataFail1() {
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, uri,
null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
if (response != null) {
Log.d(TAG, "response = " + response.toString());
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "error = " + error);
}
}) {
//將參數(shù)存儲到map中然后返回,系統(tǒng)會自動調(diào)用這個方法,將參數(shù)傳遞出去
@Override
protected Map<String, String> getParams() {
Map<String, String> map = new HashMap<String, String>();
map.put(key1, "string1");
map.put(key2, "string2");
return map;
}
};
jsonObjectRequest.setTag("post");
MyVolleyHelper.getInstance(getApplicationContext()).addToRequestQueue(jsonObjectRequest);
}
此方法是重寫Request的getParams方法,將參數(shù)傳遞給服務(wù)器。但是失敗了,沒有數(shù)據(jù)返回。
再試驗另外一種寫法:
private void postDataFail2() {
Map<String, String> map = new HashMap<String, String>();
map.put(key1, "string1");
map.put(key2, "string2");
JSONObject jsonObject = new JSONObject(map);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, uri,
jsonObject, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
if (response != null) {
Log.d(TAG, "response = " + response.toString());
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "error = " + error);
}
}) ;
jsonObjectRequest.setTag("post");
MyVolleyHelper.getInstance(getApplicationContext()).addToRequestQueue(jsonObjectRequest);
}
此方法是通過傳入JsonObjectRequest的構(gòu)造方法,但是依然失敗了。
上述2種方式實際上都沒有將參數(shù)傳遞給服務(wù)器,所以服務(wù)器當然就不會返回數(shù)據(jù)。
我們先看下getParams方法是哪里使用的。
Request.java
/**
* Returns the raw POST or PUT body to be sent.
*
* <p>By default, the body consists of the request parameters in
* application/x-www-form-urlencoded format. When overriding this method, consider overriding
* {@link #getBodyContentType()} as well to match the new body format.
*
* @throws AuthFailureError in the event of auth failure
*/
public byte[] getBody() throws AuthFailureError {
Map<String, String> params = getParams();
if (params != null && params.size() > 0) {
return encodeParameters(params, getParamsEncoding());
}
return null;
}
getBody方法會將參數(shù)轉(zhuǎn)成& = 形式傳遞過去。
而JsonObjectRequest繼承JsonRequest,來看下JsonRequest的getBody方法
@Override
public byte[] getBody() {
try {
return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET);
} catch (UnsupportedEncodingException uee) {
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
mRequestBody, PROTOCOL_CHARSET);
return null;
}
}
mRequestBody是一個string類型,并且mRequestBody就是參數(shù),必須通過構(gòu)造方法傳遞
public JsonRequest(int method, String url, String requestBody, Listener<T> listener,
ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
mRequestBody = requestBody;
}
此時,應(yīng)該就已經(jīng)很明白了,第一種方式,JsonObjectRequest重寫getParams方法根本就不會將參數(shù)傳遞上去,無效的。第二種方式傳遞的是JsonObject數(shù)據(jù),并不是String,所以同樣無法獲取到數(shù)據(jù)。
解決方案:
- 自定義CustomRequestt繼承Request,將參數(shù)通過構(gòu)造方法,在getParams方法返回這參數(shù)。
這樣就可以將參數(shù)傳遞上去。public class CustomRequest extends Request<JSONObject> { private Response.Listener<JSONObject> listener; private Map<String, String> params; public CustomRequest(String url, Map<String, String> params, Response.Listener<JSONObject> reponseListener, Response.ErrorListener errorListener) { super(Method.GET, url, errorListener); this.listener = reponseListener; this.params = params; } public CustomRequest(int method, String url, Map<String, String> params, Response.Listener<JSONObject> reponseListener, Response.ErrorListener errorListener) { super(method, url, errorListener); this.listener = reponseListener; this.params = params; } protected Map<String, String> getParams() throws com.android.volley.AuthFailureError { return params; }; @Override protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers, "utf-8")); return Response.success(new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JSONException je) { return Response.error(new ParseError(je)); } } @Override protected void deliverResponse(JSONObject response) { // TODO Auto-generated method stub listener.onResponse(response); }
}
使用方法:
~~~java
private void postDataSuccess1() {
Map<String, String> map = new HashMap<String, String>();
map.put(key1, "string1");
map.put(key2, "string2");
CustomRequest jsonObjectRequest = new CustomRequest(Request.Method.POST, uri,
map, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.d(TAG, "postThemeData2 onResponse");
if (response != null) {
Log.d(TAG, "response = " + response.toString());
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "error = " + error);
}
});
jsonObjectRequest.setTag("post");
MyVolleyHelper.getInstance(getApplicationContext()).addToRequestQueue(jsonObjectRequest);
}
-
自定義MyJsonObjectRequest繼承JsonRequest,將參數(shù)直接以string的形式傳遞。
public class MyJsonObjectRequest extends JsonRequest<JSONObject> { String stringRequest; public MyJsonObjectRequest(String url, String stringRequest, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) { super(Method.POST, url, stringRequest , listener, errorListener); this.stringRequest = stringRequest; } @Override public String getBodyContentType() { return "application/x-www-form-urlencoded; charset=" + getParamsEncoding(); } @Override protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)); return Response.success(new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JSONException je) { return Response.error(new ParseError(je)); } } }這里注意的是必須要重寫getBodyContentType方法。
使用方法:
private void postDataSuccess2() { Map<String, String> map = new HashMap<String, String>(); map.put(key1, "string1"); map.put(key2, "string2"); String params = appendParameter( uri,map); Log.d(TAG, "params = "+params); MyJsonObjectRequest jsonObjectRequest = new MyJsonObjectRequest( uri, params, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { if (response != null) { Log.d(TAG, "postDataSuccess2 response = " + response.toString()); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); MyVolleyHelper.getInstance(getApplicationContext()).addToRequestQueue(jsonObjectRequest); } ///拼接下參數(shù),轉(zhuǎn)成string private String appendParameter(String url,Map<String,String> params){ Uri uri = Uri.parse(url); Uri.Builder builder = uri.buildUpon(); for(Map.Entry<String,String> entry:params.entrySet()){ builder.appendQueryParameter(entry.getKey(),entry.getValue()); } return builder.build().getQuery(); } 還是使用JsonObjectRequest,重寫getBody 和getBodyContentType方法,保證傳遞的參數(shù)準確。
private void postDataSuccess3() {
Map<String, String> map = new HashMap<String, String>();
map.put(key1, "string1");
map.put(key2, "string2");
final String mRequestBody = appendParameter(
uri,map);
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, uri,
null, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.d(TAG, "postThemeData onResponse");
if (response != null) {
Log.d(TAG, "response = " + response.toString());
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, "error = " + error);
}
}) {
@Override
public byte[] getBody() {
try {
return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET);
} catch (UnsupportedEncodingException uee) {
VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",
mRequestBody, PROTOCOL_CHARSET);
return null;
}
}
@Override
public String getBodyContentType() {
return "application/x-www-form-urlencoded; charset=" + getParamsEncoding();
}
};
jsonObjectRequest.setTag("post");
MyVolleyHelper.getInstance(getApplicationContext()).addToRequestQueue(jsonObjectRequest);
}
上述三種寫法,都可以正確返回數(shù)據(jù)。以上做個記錄。
總結(jié)
JsonObjectRequest 請求post數(shù)據(jù)不能直接通過重寫getParams方法或者直接在構(gòu)造方法里面?zhèn)鬟f,而是需要保證getBody方法能夠真正的得到參數(shù)。
感謝
本文重點參考了http://blog.csdn.net/onlysnail/article/details/47905375和http://blog.csdn.net/Waydrow/article/details/51002721, 還有一些其他的volley文章。