首页 > 代码库 > android Volley 实现文件上传功能
android Volley 实现文件上传功能
Volley不解释了吧, android 官方的一个网络请求库.
源代码的地址在:
git@github.com:com314159/VolleyMultiPartRequest.git
是根据
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.使用方法:
/**
* 通过put来上传文件
* @param url
* @param files
* @param params
* @param responseListener
* @param errorListener
* @param tag
*/
public staticvoid addPutUploadFileRequest(final Stringurl,
final Map<String, File>files, final Map<String, String> params,
final Listener<String>responseListener, final ErrorListenererrorListener,
final Objecttag) {
if (null ==url || null == responseListener) {
return;
}
MultiPartStringRequest multiPartRequest =new MultiPartStringRequest(
Request.Method.PUT,url, responseListener, errorListener) {
@Override
public Map<String, File> getFileUploads() {
returnfiles;
}
@Override
public Map<String, String> getStringUploads() {
returnparams;
}
};
Log.i(TAG," volley put : uploadFile " + url );
MainApplication.getVolleyQueue().add(multiPartRequest);
}
android Volley 实现文件上传功能