相信 volley 絕大部分做 android 的人已經知道了,關于 volley 的使用網上也是一抓一大把,都是說 volley 如何如何好用,下面分享下自己在使用 volley 過程中踩過的坑。
volley 好用的一個原因是封裝的 api 看起來也比較直接,但是其回調的 api 做的是一般般,其中有一個 JsonObjectRequest 類,網上的使用說明也一大把,基本上都是最簡單的情形:
Get 請求示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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 請求示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
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&amp;lt;JSONObject&amp;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 的參數!看源碼:
1 2 3 4 5 6 7 8 9 10 11 |
//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 來傳遞。于是做了如下修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
String query = ""; if (mParams != null) { Uri uri = Uri.parse(mUrl); Uri.Builder builder = uri.buildUpon(); for (HashMap.Entry&amp;lt;String, String&amp;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&amp;lt;JSONObject&amp;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
1 2 3 4 5 6 7 |
@Override public String getBodyContentType() { if (getMethod() == Method.POST) { return "application/x-www-form-urlencoded"; } return super.getBodyContentType(); } |
搞定了!
這里是不是還有人在想 get 請求如何傳參數的?用這種方式怎么 get 請求不能傳參,其實也是非常簡單,在請求時 url 就帶上 key=value 就好!如:
1 2 3 4 5 6 7 8 9 10 |
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 的同學有幫助~~
李白 2017 年 3 月 30 日
找外包,想要穩定靠譜、費用還低的外包商?難!
怕被坑?上空心 www.kxhtml.com 一家 100 元/頁的軟件開發云平臺!
在招人,海招海篩、培訓,到頭來上手還是慢!
用結果打臉!上空心 www.kxhtml.com 一家先看開發結果后付費的平臺!
想創業,有 idea? 到處找 CTO? 技術難關攻不破?
立即上線!上空心 www.kxhtml.com 一家開發神速火箭般輸出頁面的平臺!
川 2015 年 6 月 18 日
使用 okvolley 吧, 對參數都進行了進一步封裝, 而且還用到了 okhttp 做網絡層的請求.
Cmdmac 2015 年 6 月 22 日
volley 我其實也只是在個別項目里用了下,其實 okhttp 和 Retrofit 也不錯~~