用Volley踩過的坑

jopen 9年前發布 | 50K 次閱讀 Volley Android開發 移動開發

相信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&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的參數!看源碼:
//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&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
@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 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!