源代码的地址在:
git@github.com:com314159/VolleyMultiPartRequest.git
上面的是ssh
下面的是http地址
https://github.com/com314159/VolleyMultiPartRequest
是根据
https://github.com/smanikandan14/Volley-demo
这位大神修改而来的, 但是那位大神的代码有bug, 上传文件不成功.
注: 我的demo里面还集成了okhttp, 不需要的同学不用理这个类即可
实现方法:
1.添加三个jar包,
httpcore-4.3.2.jar
httpclient-4.3.5.jar
httpmime-4.3.5.jar
2.实现MultiPartStack
- package com.example.volleytest;
- import java.io.File;
- import java.io.IOException;
- import java.util.Map;
- import org.apache.http.HttpEntity;
- import org.apache.http.HttpResponse;
- import org.apache.http.client.HttpClient;
- import org.apache.http.client.methods.HttpDelete;
- import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
- import org.apache.http.client.methods.HttpGet;
- import org.apache.http.client.methods.HttpPatch;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.client.methods.HttpPut;
- import org.apache.http.client.methods.HttpUriRequest;
- import org.apache.http.entity.ByteArrayEntity;
- import org.apache.http.entity.ContentType;
- import org.apache.http.entity.mime.HttpMultipartMode;
- import org.apache.http.entity.mime.MultipartEntityBuilder;
- import org.apache.http.entity.mime.content.FileBody;
- import org.apache.http.entity.mime.content.StringBody;
- import org.apache.http.impl.client.DefaultHttpClient;
- import org.apache.http.params.HttpConnectionParams;
- import org.apache.http.params.HttpParams;
- import org.apache.http.protocol.HTTP;
- import com.android.volley.AuthFailureError;
- import com.android.volley.Request;
- import com.android.volley.Request.Method;
- import com.android.volley.toolbox.HurlStack;
- /**
- * @author ZhiCheng Guo
- * @version 2014年10月7日 上午11:00:52 这个Stack用于上传文件, 如果没有这个Stack, 则上传文件不成功
- */
- public class MultiPartStack extends HurlStack {
- @SuppressWarnings("unused")
- private static final String TAG = MultiPartStack.class.getSimpleName();
- private final static String HEADER_CONTENT_TYPE = "Content-Type";
- @Override
- public HttpResponse performRequest(Request<?> request,
- Map<String, String> additionalHeaders) throws IOException, AuthFailureError {
- if(!(request instanceof MultiPartRequest)) {
- return super.performRequest(request, additionalHeaders);
- }
- else {
- return performMultiPartRequest(request, additionalHeaders);
- }
- }
- private static void addHeaders(HttpUriRequest httpRequest, Map<String, String> headers) {
- for (String key : headers.keySet()) {
- httpRequest.setHeader(key, headers.get(key));
- }
- }
- public HttpResponse performMultiPartRequest(Request<?> request,
- Map<String, String> additionalHeaders) throws IOException, AuthFailureError {
- HttpUriRequest httpRequest = createMultiPartRequest(request, additionalHeaders);
- addHeaders(httpRequest, additionalHeaders);
- addHeaders(httpRequest, request.getHeaders());
- HttpParams httpParams = httpRequest.getParams();
- int timeoutMs = request.getTimeoutMs();
- // TODO: Reevaluate this connection timeout based on more wide-scale
- // data collection and possibly different for wifi vs. 3G.
- HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
- HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
- /* Make a thread safe connection manager for the client */
- HttpClient httpClient = new DefaultHttpClient(httpParams);
- return httpClient.execute(httpRequest);
- }
- static HttpUriRequest createMultiPartRequest(Request<?> request,
- Map<String, String> additionalHeaders) throws AuthFailureError {
- switch (request.getMethod()) {
- case Method.DEPRECATED_GET_OR_POST: {
- // This is the deprecated way that needs to be handled for backwards compatibility.
- // If the request's post body is null, then the assumption is that the request is
- // GET. Otherwise, it is assumed that the request is a POST.
- byte[] postBody = request.getBody();
- if (postBody != null) {
- HttpPost postRequest = new HttpPost(request.getUrl());
- if(request.getBodyContentType() != null)
- postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
- HttpEntity entity;
- entity = new ByteArrayEntity(postBody);
- postRequest.setEntity(entity);
- return postRequest;
- } else {
- return new HttpGet(request.getUrl());
- }
- }
- case Method.GET:
- return new HttpGet(request.getUrl());
- case Method.DELETE:
- return new HttpDelete(request.getUrl());
- case Method.POST: {
- HttpPost postRequest = new HttpPost(request.getUrl());
- postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
- setMultiPartBody(postRequest,request);
- return postRequest;
- }
- case Method.PUT: {
- HttpPut putRequest = new HttpPut(request.getUrl());
- if(request.getBodyContentType() != null)
- putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
- setMultiPartBody(putRequest,request);
- return putRequest;
- }
- // Added in source code of Volley libray.
- case Method.PATCH: {
- HttpPatch patchRequest = new HttpPatch(request.getUrl());
- if(request.getBodyContentType() != null)
- patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());
- return patchRequest;
- }
- default:
- throw new IllegalStateException("Unknown request method.");
- }
- }
- /**
- * If Request is MultiPartRequest type, then set MultipartEntity in the
- * httpRequest object.
- *
- * @param httpRequest
- * @param request
- * @throws AuthFailureError
- */
- private static void setMultiPartBody(HttpEntityEnclosingRequestBase httpRequest,
- Request<?> request) throws AuthFailureError {
- // Return if Request is not MultiPartRequest
- if (!(request instanceof MultiPartRequest)) {
- return;
- }
- // MultipartEntity multipartEntity = new
- // MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
- MultipartEntityBuilder builder = MultipartEntityBuilder.create();
- /* example for setting a HttpMultipartMode */
- builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
- // Iterate the fileUploads
- Map<String, File> fileUpload = ((MultiPartRequest) request).getFileUploads();
- for (Map.Entry<String, File> entry : fileUpload.entrySet()) {
- builder.addPart(((String) entry.getKey()), new FileBody((File) entry.getValue()));
- }
- ContentType contentType = ContentType.create(HTTP.PLAIN_TEXT_TYPE, HTTP.UTF_8);
- // Iterate the stringUploads
- Map<String, String> stringUpload = ((MultiPartRequest) request).getStringUploads();
- for (Map.Entry<String, String> entry : stringUpload.entrySet()) {
- try {
- builder.addPart(((String) entry.getKey()),
- new StringBody((String) entry.getValue(), contentType));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- httpRequest.setEntity(builder.build());
- }
- }
3. 实现MultiPartRequest, 这个接口是为了方便扩展
- package com.example.volleytest;
- import java.io.File;
- import java.util.Map;
- /**
- * @author ZhiCheng Guo
- * @version 2014年10月7日 上午11:04:36
- */
- public interface MultiPartRequest {
- public void addFileUpload(String param,File file);
- public void addStringUpload(String param,String content);
- public Map<String,File> getFileUploads();
- public Map<String,String> getStringUploads();
- }
- /**
- * Copyright 2013 Mani Selvaraj
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.example.volleytest;
- import java.io.File;
- import java.io.UnsupportedEncodingException;
- import java.util.HashMap;
- import java.util.Map;
- import com.android.volley.NetworkResponse;
- import com.android.volley.Request;
- import com.android.volley.Response;
- import com.android.volley.Response.ErrorListener;
- import com.android.volley.Response.Listener;
- import com.android.volley.toolbox.HttpHeaderParser;
- /**
- * MultipartRequest - To handle the large file uploads.
- * Extended from JSONRequest. You might want to change to StringRequest based on your response type.
- * @author Mani Selvaraj
- *
- */
- public class MultiPartStringRequest extends Request<String> implements MultiPartRequest{
- private final Listener<String> mListener;
- /* To hold the parameter name and the File to upload */
- private Map<String,File> fileUploads = new HashMap<String,File>();
- /* To hold the parameter name and the string content to upload */
- private Map<String,String> stringUploads = new HashMap<String,String>();
- /**
- * Creates a new request with the given method.
- *
- * @param method the request {@link Method} to use
- * @param url URL to fetch the string at
- * @param listener Listener to receive the String response
- * @param errorListener Error listener, or null to ignore errors
- */
- public MultiPartStringRequest(int method, String url, Listener<String> listener,
- ErrorListener errorListener) {
- super(method, url, errorListener);
- mListener = listener;
- }
- public void addFileUpload(String param,File file) {
- fileUploads.put(param,file);
- }
- public void addStringUpload(String param,String content) {
- stringUploads.put(param,content);
- }
- /**
- * 要上传的文件
- */
- public Map<String,File> getFileUploads() {
- return fileUploads;
- }
- /**
- * 要上传的参数
- */
- public Map<String,String> getStringUploads() {
- return stringUploads;
- }
- @Override
- protected Response<String> parseNetworkResponse(NetworkResponse response) {
- 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));
- }
- @Override
- protected void deliverResponse(String response) {
- if(mListener != null) {
- mListener.onResponse(response);
- }
- }
- /**
- * 空表示不上传
- */
- public String getBodyContentType() {
- return null;
- }
- }
3.使用方法和volley原生的request的使用方法是一样的, 只是要使用新的Stack, 如下面的是put的方法的使用方法. 如果是post, 就修改成post方法就可以了
RequestQueue mSingleQueue = Volley.newRequestQueue(this, new MultiPartStack());
MultiPartStringRequest multiPartRequest = new MultiPartStringRequest(
Request.Method.PUT, url, responseListener, errorListener) {
@Override
public Map<String, File> getFileUploads() {
return files;
}
@Override
public Map<String, String> getStringUploads() {
return params;
}
};
mSingeQueue.add(multiPartRequest)