1、前言java
Google自從2013的IO大會上發佈volley框架以後就受到普遍應用,的確,用過幾個網絡請求庫,感受volley仍是很好用的,用起來也特別方便順手。可是遇到上傳文件就比較麻煩,尤爲是有時候想一個參數名對應多個文件,就像我坑爹後臺給個人接口,就是參數的key叫作images,而後value是多圖。。多圖。。。圖。。。。android
有許多網絡請求庫的post請求時,帶參數使用hashmap進行封裝的,可是hashmap是以鍵值對形式存值的,這裏有一個問題就是一個key對應一個value,當你連續put進去兩個key是同樣的時候,後者就會將前者取代掉。最後只剩下一個參數而已。這樣是達不到需求的。而有一個解決辦法就是開多個子線程,每次傳一張圖片過去,其實這樣也行,具體仍是看需求,我這裏要討論的是一次性傳多圖。apache
2、解決服務器
而若是使用volley的話,由於請求數據那些都很簡便,但遇到上傳文件就麻煩那可很差,同時使用多個網絡請求類庫也是不太建議的。因此這裏就給出了一種解決方法,也要藉助一個jar包,這裏用到的是httpmime(點擊下載),主要用到的是MultipartEntity類,能夠對請求參數進行封裝。網絡
主要是繼承volley的Request類,而後經過使用httpmim的MultipartEntity類對文件參數進行封裝,這裏實現了一個參數名對應一個文件,框架
一個參數名對應多個文件,若是還要多個參數名對應多個文件能夠本身試着實現一下哈:
ide
package com.android.volley.toolbox; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import com.android.volley.AuthFailureError; import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyLog; import com.common.utils.CLog; import com.common.utils.FileUtil; public class MultipartRequest extends Request<String> { private MultipartEntity entity = new MultipartEntity(); private final Response.Listener<String> mListener; private List<File> mFileParts; private String mFilePartName; private Map<String, String> mParams; /** * 單個文件 * @param url * @param errorListener * @param listener * @param filePartName * @param file * @param params */ public MultipartRequest(String url, Response.ErrorListener errorListener, Response.Listener<String> listener, String filePartName, File file, Map<String, String> params) { super(Method.POST, url, errorListener); mFileParts = new ArrayList<File>(); if (file != null) { mFileParts.add(file); } mFilePartName = filePartName; mListener = listener; mParams = params; buildMultipartEntity(); } /** * 多個文件,對應一個key * @param url * @param errorListener * @param listener * @param filePartName * @param files * @param params */ public MultipartRequest(String url, Response.ErrorListener errorListener, Response.Listener<String> listener, String filePartName, List<File> files, Map<String, String> params) { super(Method.POST, url, errorListener); mFilePartName = filePartName; mListener = listener; mFileParts = files; mParams = params; buildMultipartEntity(); } private void buildMultipartEntity() { if (mFileParts != null && mFileParts.size() > 0) { for (File file : mFileParts) { entity.addPart(mFilePartName, new FileBody(file)); } long l = entity.getContentLength(); CLog.log(mFileParts.size()+"個,長度:"+l); } try { if (mParams != null && mParams.size() > 0) { for (Map.Entry<String, String> entry : mParams.entrySet()) { entity.addPart( entry.getKey(), new StringBody(entry.getValue(), Charset .forName("UTF-8"))); } } } catch (UnsupportedEncodingException e) { VolleyLog.e("UnsupportedEncodingException"); } } @Override public String getBodyContentType() { return entity.getContentType().getValue(); } @Override public byte[] getBody() throws AuthFailureError { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { entity.writeTo(bos); } catch (IOException e) { VolleyLog.e("IOException writing to ByteArrayOutputStream"); } return bos.toByteArray(); } @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { CLog.log("parseNetworkResponse"); if (VolleyLog.DEBUG) { if (response.headers != null) { for (Map.Entry<String, String> entry : response.headers .entrySet()) { VolleyLog.d(entry.getKey() + "=" + entry.getValue()); } } } String parsed; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException e) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); } /* * (non-Javadoc) * * @see com.android.volley.Request#getHeaders() */ @Override public Map<String, String> getHeaders() throws AuthFailureError { VolleyLog.d("getHeaders"); Map<String, String> headers = super.getHeaders(); if (headers == null || headers.equals(Collections.emptyMap())) { headers = new HashMap<String, String>(); } return headers; } @Override protected void deliverResponse(String response) { mListener.onResponse(response); } }
經過這個請求就能夠上傳多文件了,也不作多解釋,代碼也比較簡單。我也對這種方法測試過了,可是因爲是和服務器進行打交道,這裏確實沒有什麼能夠展現出來,不過我仍是喜歡有說服力的描述,所謂有圖有真相哈哈,上兩個圖在作解釋post