使用最新 API 通过 Volley 处理 POST 多部分请求
在 Android 开发中,发送多部分请求(例如上传文件和文本数据)是一项共同的任务。虽然 HttpEntity 在较新的 API 版本中不再可用,但仍然有一些方法可以使用 Volley 实现多部分请求。
创建基本多部分请求
创建多部分请求,我们可以像这样扩展 Volley 的 Request 类:
import com.android.volley.AuthFailureError; import com.android.volley.NetworkResponse; import com.android.volley.ParseError; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.HttpHeaderParser; import java.util.Map; class MultipartRequest extends Request<NetworkResponse> { // Listener for request response private final Response.Listener<NetworkResponse> mListener; // Listener for request error private final Response.ErrorListener mErrorListener; // Request headers private final Map<String, String> mHeaders; // Multipart mime type (e.g., "multipart/form-data; boundary=XXX") private final String mMimeType; // Request body as multipart private final byte[] mMultipartBody; // Constructor public MultipartRequest(String url, Map<String, String> headers, String mimeType, byte[] multipartBody, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) { super(Method.POST, url, errorListener); this.mListener = listener; this.mErrorListener = errorListener; this.mHeaders = headers; this.mMimeType = mimeType; this.mMultipartBody = multipartBody; } // Getters and setters // Override getHeaders() if you need to add custom headers @Override public Map<String, String> getHeaders() throws AuthFailureError { return (mHeaders != null) ? mHeaders : super.getHeaders(); } // Override getBodyContentType() to set the correct mime type for the multipart request @Override public String getBodyContentType() { return mMimeType; } // Override getBody() to return the multipart body @Override public byte[] getBody() throws AuthFailureError { return mMultipartBody; } // Override parseNetworkResponse() to parse the response as a NetworkResponse @Override protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) { try { return Response.success( response, HttpHeaderParser.parseCacheHeaders(response)); } catch (Exception e) { return Response.error(new ParseError(e)); } } // Delivering response and error @Override protected void deliverResponse(NetworkResponse response) { mListener.onResponse(response); } @Override public void deliverError(VolleyError error) { mErrorListener.onErrorResponse(error); } }
构建多部分主体
要构建多部分主体,我们可以使用以下步骤:
byte[] multipartBody = new byte[0]; ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); try { // Text data buildTextPart(dos, "name", "John Doe"); buildTextPart(dos, "email", "john.doe@email.com"); // Image data Bitmap imageBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.my_image); buildImagePart(dos, "image", imageBitmap); } catch (IOException e) { e.printStackTrace(); } multipartBody = bos.toByteArray();
在请求中包含多部分主体
一旦构建了多部分主体,我们就可以将其包含在我们的 MultipartRequest 实例中,例如so:
MultipartRequest request = new MultipartRequest( "my_url", null, // Headers "multipart/form-data", multipartBody, new Response.Listener<NetworkResponse>() { @Override public void onResponse(NetworkResponse response) { // Handle response } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // Handle error } });
在请求中添加文本数据
除了图像数据,您还可以在请求中包含文本数据:
private void buildTextPart(DataOutputStream dataOutputStream, String name, String value) throws IOException { dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd); dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + name + "\"" + lineEnd); dataOutputStream.writeBytes(lineEnd); dataOutputStream.writeBytes(value); dataOutputStream.writeBytes(lineEnd); }
将两个连字符、边界和 lineEnd 替换为您的适当值code.
完整代码示例
以下代码示例显示了 VolleyMultipartRequest 类的完整模块化实现:
import com.android.volley.AuthFailureError; import com.android.volley.NetworkResponse; import com.android.volley.ParseError; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.HttpHeaderParser; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class VolleyMultipartRequest extends Request<NetworkResponse> { private final Response.Listener<NetworkResponse> mListener; private final Response.ErrorListener mErrorListener; private final Map<String, String> mHeaders; private final String mMimeType; private final byte[] mMultipartBody; public VolleyMultipartRequest(int method, String url, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) { super(method, url, errorListener); this.mListener = listener; this.mErrorListener = errorListener; this.mHeaders = null; this.mMimeType = null; this.mMultipartBody = null; } public VolleyMultipartRequest(String url, Map<String, String> headers, String mimeType, byte[] multipartBody, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) { super(Method.POST, url, errorListener); this.mListener = listener; this.mErrorListener = errorListener; this.mHeaders = headers; this.mMimeType = mimeType; this.mMultipartBody = multipartBody; } @Override public Map<String, String> getHeaders() throws AuthFailureError { return (mHeaders != null) ? mHeaders : super.getHeaders(); } @Override public String getBodyContentType() { return mMimeType; } @Override public byte[] getBody() throws AuthFailureError { return mMultipartBody; } @Override protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) { try { return Response.success( response, HttpHeaderParser.parseCacheHeaders(response)); } catch (Exception e) { return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(NetworkResponse response) { mListener.onResponse(response); } @Override public void deliverError(VolleyError error) { mErrorListener.onErrorResponse(error); } public static Map<String, DataPart> createMultipartRequestParts(Map<String, String> params, Map<String, DataPart> data) { Map<String, DataPart> multipartParams = new HashMap<>(); for (Map.Entry<String, String> entry : params.entrySet()) { multipartParams.put(entry.getKey(), new DataPart(entry.getValue())); } for (Map.Entry<String, DataPart> entry : data.entrySet()) { multipartParams.put(entry.getKey(), entry.getValue()); } return multipartParams; } public static byte[] createMultipartBody(Map<String, DataPart> data, String boundary) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); for (Map.Entry<String, DataPart> entry : data.entrySet()) { buildTextPart(dos, entry.getKey(), entry.getValue().getContentType(), entry.getValue().getFileName(), entry.getValue().getData()); }
以上是如何在 Android 中使用 Volley 发出有效的 POST 多部分请求?的详细内容。更多信息请关注PHP中文网其他相关文章!