用Volley踩過的坑
相信volley絕大部分做android的人已經知道了,關于volley的使用網上也是一抓一大把,都是說volley如何如何好用,下面分享下自己在使用volley過程中踩過的坑。
volley好用的一個原因是封裝的api看起來也比較直接,但是其回調的api做的是一般般,其中有一個JsonObjectRequest類,網上的使用說明也一大把,基本上都是最簡單的情形:
Get請求示例:
RequestQueue queue = Volley.newRequestQueue(this); String url = "http://m.weather.com.cn/data/101201401.html"; JsonObjectRequest objRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject obj) { System.out.println("----------:" + obj); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { error.getMessage(); } }); objRequest.setTag("obj"); queue.add(objRequest);
Post請求示例:
Map<String,String> map=new HashMap<String,String>(); map.put("token", "AbCdEfGh123456"); JSONObject params=new JSONObject(map); RequestQueue queue = Volley.newRequestQueue(this); String url = "http://m.weather.com.cn/data/101201401.html"; JsonObjectRequest objRequest = new JsonObjectRequest(url, params, new Response.Listener&lt;JSONObject&gt;() { @Override public void onResponse(JSONObject obj) { System.out.println("----------:" + obj); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { error.getMessage(); } });
上面的兩個例子是使用的最簡單的情形,就是Get和Post請求都沒有帶上參數,于是百度這個問題得到的答案都是說通過 JsonObjectRequest的JsonObject jsonRequest這個參數來指定,官方的文檔對這個參數說的也是不清不楚的,這個地方看了半天也想不通參數為什么會是用json對象來傳遞,不應該是key=value的形式嗎?又多百度了幾遍,說是通過自定義JsonObjectRequest然后通過override其getParams函數來指定,但照做后這個函數不會被調用。。。百般無奈下只能看源碼了,看了源碼才發現JsonObjectRequest的構造函數里的 jsonRequest參數其實最終把JsonObject轉換成String,如果這個對象是空的,那么會默認以get請求(除非你指定是用 post),否則這個參數會當做是post的參數!看源碼:
//JsonRequest.java @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; } }
具體getBody在哪里被調用就不具體來培析,有興趣的可自己研究源碼,看到這個,如果是說想繼承JsonOjectRequest又想用 key=value&key1=value1的形式來做參數的話肯定是想到了自定義的類里構造mRequestBody也就是 JsonObject轉換成String的地方用String(key=value形式)來代替用JsonObject來傳遞。于是做了如下修改:
String query = ""; if (mParams != null) { Uri uri = Uri.parse(mUrl); Uri.Builder builder = uri.buildUpon(); for (HashMap.Entry&lt;String, String&gt; entry : mParams.entrySet()) { builder.appendQueryParameter(entry.getKey(), entry.getValue()); } query = builder.build().getEncodedQuery(); } else { } mRequest = new MyJsonObjectRequest(mUrl, query, this, this); //MyJsonObjectRequest.java 繼承JsonObjectRequest public MyJsonObjectRequest(String url, String params, Response.Listener&lt;JSONObject&gt; listener, Response.ErrorListener errorListener) { super(Method.POST, url, params, listener, errorListener); }
但最終還是不行!為什么? 參數傳遞沒有錯誤啊?事實上這里忘了一個非常重要的地方,也就是post請求的header,在發起key=value形式的參數時,我們請求的 Content-Type應該是application/x-www-form-urlencoded的,而JsonRequest默認是 application/json; charset=%s,這就是真相,于是重寫getBodyContentType
@Override public String getBodyContentType() { if (getMethod() == Method.POST) { return "application/x-www-form-urlencoded"; } return super.getBodyContentType(); }
搞定了!
這里是不是還有人在想get請求如何傳參數的?用這種方式怎么get請求不能傳參,其實也是非常簡單,在請求時url就帶上key=value就好!如:
if (mParams != null) { Uri uri = Uri.parse(url); Uri.Builder builder = uri.buildUpon(); for (HashMap.Entry<String, String> entry : mParams.entrySet()) { builder.appendQueryParameter(entry.getKey(), entry.getValue()); } mUrl = builder.build().toString(); } else { mUrl = url; }
聰明的你肯定想到了吧,希望給同樣用volley的同學有幫助~~
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!