1. 程式人生 > >Android volley(5)MultipartEntity 封裝 volley上傳 —— 一個引數多張圖、多張圖片多張圖

Android volley(5)MultipartEntity 封裝 volley上傳 —— 一個引數多張圖、多張圖片多張圖

一、前言

Google自從2013的IO大會上釋出volley框架之後就受到廣泛應用,的確,用過幾個網路請求庫,感覺volley還是很好用的,用起來也特別方便順手。但是遇到上傳檔案就比較麻煩,尤其是有時候想一個引數名對應多個檔案,就像我坑爹後臺給我的介面,就是引數的key叫做images,然後value是多圖。。多圖。。。圖。。。。

有許多網路請求庫的post請求時,帶引數使用hashmap進行封裝的,但是hashmap是以鍵值對形式存值的,這裡有一個問題就是一個key對應一個value,當你連續put進去兩個key是一樣的時候,後者就會將前者取代掉。最後只剩下一個引數而已。這樣是達不到需求的。而有一個解決辦法就是開多個子執行緒,每次傳一張圖片過去,其實這樣也行,具體還是看需求,我這裡要討論的是一次性傳多圖。

二、解決

而如果使用volley的話,因為請求資料那些都很簡便,但遇到上傳檔案就麻煩那可不好,同時使用多個網路請求類庫也是不太建議的。所以這裡就給出了一種解決方法,也要藉助一個jar包,這裡用到的是httpmime(點選下載),主要用到的是MultipartEntity類,可以對請求引數進行封裝。

主要是繼承volley的Request類,然後通過使用httpmim的MultipartEntity類對檔案引數進行封裝,這裡實現了一個引數名對應一個檔案,

一個引數名對應多個檔案,如果還要多個引數名對應多個檔案可以自己試著實現一下哈

  1. package com.android.volley.toolbox;  
  2. import java.io.ByteArrayOutputStream;  
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.io.UnsupportedEncodingException;  
  6. import java.nio.charset.Charset;  
  7. import java.util.ArrayList;  
  8. import java.util.Collections;  
  9. import java.util.HashMap;  
  10. import java.util.List;  
  11. import java.util.Map;  
  12. import org.apache.http.entity.mime.MultipartEntity;  
  13. import org.apache.http.entity.mime.content.FileBody;  
  14. import org.apache.http.entity.mime.content.StringBody;  
  15. import com.android.volley.AuthFailureError;  
  16. import com.android.volley.NetworkResponse;  
  17. import com.android.volley.Request;  
  18. import com.android.volley.Response;  
  19. import com.android.volley.VolleyLog;  
  20. import com.common.utils.CLog;  
  21. import com.common.utils.FileUtil;  
  22. publicclass MultipartRequest extends Request<String> {  
  23.     private MultipartEntity entity = new MultipartEntity();  
  24.     privatefinal Response.Listener<String> mListener;  
  25.     private List<File> mFileParts;  
  26.     private String mFilePartName;  
  27.     private Map<String, String> mParams;  
  28.     /** 
  29.      * 單個檔案 
  30.      * @param url 
  31.      * @param errorListener 
  32.      * @param listener 
  33.      * @param filePartName 
  34.      * @param file 
  35.      * @param params 
  36.      */
  37.     public MultipartRequest(String url, Response.ErrorListener errorListener,  
  38.             Response.Listener<String> listener, String filePartName, File file,  
  39.             Map<String, String> params) {  
  40.         super(Method.POST, url, errorListener);  
  41.         mFileParts = new ArrayList<File>();  
  42.         if (file != null) {  
  43.             mFileParts.add(file);  
  44.         }  
  45.         mFilePartName = filePartName;  
  46.         mListener = listener;  
  47.         mParams = params;  
  48.         buildMultipartEntity();  
  49.     }  
  50.     /** 
  51.      * 多個檔案,對應一個key 
  52.      * @param url 
  53.      * @param errorListener 
  54.      * @param listener 
  55.      * @param filePartName 
  56.      * @param files 
  57.      * @param params 
  58.      */
  59.     public MultipartRequest(String url, Response.ErrorListener errorListener,  
  60.             Response.Listener<String> listener, String filePartName,  
  61.             List<File> files, Map<String, String> params) {  
  62.         super(Method.POST, url, errorListener);  
  63.         mFilePartName = filePartName;  
  64.         mListener = listener;  
  65.         mFileParts = files;  
  66.         mParams = params;  
  67.         buildMultipartEntity();  
  68.     }  
  69.     privatevoid buildMultipartEntity() {  
  70.         if (mFileParts != null && mFileParts.size() > 0) {  
  71.             for (File file : mFileParts) {  
  72.                 entity.addPart(mFilePartName, new FileBody(file));  
  73.             }  
  74.             long l = entity.getContentLength();  
  75.             CLog.log(mFileParts.size()+"個,長度:"+l);  
  76.         }  
  77.         try {  
  78.             if (mParams != null && mParams.size() > 0) {  
  79.                 for (Map.Entry<String, String> entry : mParams.entrySet()) {  
  80.                     entity.addPart(  
  81.                             entry.getKey(),  
  82.                             new StringBody(entry.getValue(), Charset  
  83.                                     .forName("UTF-8")));  
  84.                 }  
  85.             }  
  86.         } catch (UnsupportedEncodingException e) {  
  87.             VolleyLog.e("UnsupportedEncodingException");  
  88.         }  
  89.     }  
  90.     @Override
  91.     public String getBodyContentType() {  
  92.         return entity.getContentType().getValue();  
  93.     }  
  94.     @Override
  95.     publicbyte[] getBody() throws AuthFailureError {  
  96.         ByteArrayOutputStream bos = new ByteArrayOutputStream();  
  97.         try {  
  98.             entity.writeTo(bos);  
  99.         } catch (IOException e) {  
  100.             VolleyLog.e("IOException writing to ByteArrayOutputStream");  
  101.         }  
  102.         return bos.toByteArray();  
  103.     }  
  104.     @Override
  105.     protected Response<String> parseNetworkResponse(NetworkResponse response) {  
  106.         CLog.log("parseNetworkResponse");  
  107.         if (VolleyLog.DEBUG) {  
  108.             if (response.headers != null) {  
  109.                 for (Map.Entry<String, String> entry : response.headers  
  110.                         .entrySet()) {  
  111.                     VolleyLog.d(entry.getKey() + "=" + entry.getValue());  
  112.                 }  
  113.             }  
  114.         }  
  115.         String parsed;  
  116.         try {  
  117.             parsed = new String(response.data,  
  118.                     HttpHeaderParser.parseCharset(response.headers));  
  119.         } catch (UnsupportedEncodingException e) {  
  120.             parsed = new String(response.data);  
  121.         }  
  122.         return Response.success(parsed,  
  123.                 HttpHeaderParser.parseCacheHeaders(response));  
  124.     }  
  125.     /* 
  126.      * (non-Javadoc) 
  127.      *  
  128.      * @see com.android.volley.Request#getHeaders() 
  129.      */
  130.     @Override
  131.     public Map<String, String> getHeaders() throws AuthFailureError {  
  132.         VolleyLog.d("getHeaders");  
  133.         Map<String, String> headers = super.getHeaders();  
  134.         if (headers == null || headers.equals(Collections.emptyMap())) {  
  135.             headers = new HashMap<String, String>();  
  136.         }  
  137.         return headers;  
  138.     }  
  139.     @Override
  140.     protectedvoid deliverResponse(String response) {  
  141.         mListener.onResponse(response);  
  142.     }  
  143. }  

通過這個請求就可以上傳多檔案了,也不做多解釋,程式碼也比較簡單。我也對這種方法測試過了,但是由於是和伺服器進行打交道,這裡確實沒有什麼可以展示出來,不過我還是喜歡有說服力的描述,所謂有圖有真相哈哈,上兩個圖在做解釋


這裡是從我的log截下來的兩張圖,圖一是我裝進5個相同檔案之後打印出entity的大小,顯示是8347505位元組,圖二是我裝進3個相同檔案(跟前

面5個的檔案都是一樣的)之後打印出的大小,是5005805位元組,我相