使用Volley和不使用HttpEntity的POST多部分请求

这不是一个真正的问题,但是,我想分享一些我的工作代码在这里供您参考,当你需要的时候。

因为我们知道HttpEntity已经从API22中弃用了,并且从API23开始就被删除了。 目前,我们无法再访问Android Developer上的HttpEntity Reference (404)。 所以,以下是我的工作示例代码,用于使用Volley而不使用HttpEntity的POST Multipart Request 。 它的工作,用Asp.Net Web API进行测试。 当然,这个代码也许只是一个基本的样本,而且它并不是所有情况下的最佳解决方案,也不是所有的可调整文件。

任何建议更好/更美丽的代码将不胜感激。

希望这可以帮助!

MultipartActivity.java:

 package com.example.multipartvolley; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.v4.content.ContextCompat; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; import com.android.volley.NetworkResponse; import com.android.volley.Response; import com.android.volley.VolleyError; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; public class MultipartActivity extends Activity { private final Context context = this; private final String twoHyphens = "--"; private final String lineEnd = "\r\n"; private final String boundary = "apiclient-" + System.currentTimeMillis(); private final String mimeType = "multipart/form-data;boundary=" + boundary; private byte[] multipartBody; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_multipart); byte[] fileData1 = getFileDataFromDrawable(context, R.drawable.ic_action_android); byte[] fileData2 = getFileDataFromDrawable(context, R.drawable.ic_action_book); ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); try { // the first file buildPart(dos, fileData1, "ic_action_android.png"); // the second file buildPart(dos, fileData2, "ic_action_book.png"); // send multipart form data necesssary after file data dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); // pass to multipart body multipartBody = bos.toByteArray(); } catch (IOException e) { e.printStackTrace(); } String url = "http://192.168.1.100/api/postfile"; MultipartRequest multipartRequest = new MultipartRequest(url, null, mimeType, multipartBody, new Response.Listener<NetworkResponse>() { @Override public void onResponse(NetworkResponse response) { Toast.makeText(context, "Upload successfully!", Toast.LENGTH_SHORT).show(); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Toast.makeText(context, "Upload failed!\r\n" + error.toString(), Toast.LENGTH_SHORT).show(); } }); VolleySingleton.getInstance(context).addToRequestQueue(multipartRequest); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_multipart, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } private void buildPart(DataOutputStream dataOutputStream, byte[] fileData, String fileName) throws IOException { dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd); dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"uploaded_file\"; filename=\"" + fileName + "\"" + lineEnd); dataOutputStream.writeBytes(lineEnd); ByteArrayInputStream fileInputStream = new ByteArrayInputStream(fileData); int bytesAvailable = fileInputStream.available(); int maxBufferSize = 1024 * 1024; int bufferSize = Math.min(bytesAvailable, maxBufferSize); byte[] buffer = new byte[bufferSize]; // read file and write it into form... int bytesRead = fileInputStream.read(buffer, 0, bufferSize); while (bytesRead > 0) { dataOutputStream.write(buffer, 0, bufferSize); bytesAvailable = fileInputStream.available(); bufferSize = Math.min(bytesAvailable, maxBufferSize); bytesRead = fileInputStream.read(buffer, 0, bufferSize); } dataOutputStream.writeBytes(lineEnd); } private byte[] getFileDataFromDrawable(Context context, int id) { Drawable drawable = ContextCompat.getDrawable(context, id); Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream); return byteArrayOutputStream.toByteArray(); } } 

MultipartRequest.java:

 package com.example.multipartvolley; 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> { 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 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; } @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); } } 

更新:

对于文本部分,请参阅下面的@ RacZo的答案。

我重写你的代码@RacZo和@BNK更模块化,易于使用

 VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, url, new Response.Listener<NetworkResponse>() { @Override public void onResponse(NetworkResponse response) { String resultResponse = new String(response.data); // parse success output } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { error.printStackTrace(); } }) { @Override protected Map<String, String> getParams() { Map<String, String> params = new HashMap<>(); params.put("api_token", "gh659gjhvdyudo973823tt9gvjf7i6ric75r76"); params.put("name", "Angga"); params.put("location", "Indonesia"); params.put("about", "UI/UX Designer"); params.put("contact", "angga@email.com"); return params; } @Override protected Map<String, DataPart> getByteData() { Map<String, DataPart> params = new HashMap<>(); // file name could found file base or direct access from real path // for now just get bitmap data from ImageView params.put("avatar", new DataPart("file_avatar.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mAvatarImage.getDrawable()), "image/jpeg")); params.put("cover", new DataPart("file_cover.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mCoverImage.getDrawable()), "image/jpeg")); return params; } }; VolleySingleton.getInstance(getBaseContext()).addToRequestQueue(multipartRequest); 

在我的要点检查完整的代码VolleyMultipartRequest

好的回答@BNK!

只是想添加到答案…我试图计算如何将文本字段添加到正文,并创建以下功能来做到这一点:

 private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException { dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd); dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd); dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd); dataOutputStream.writeBytes(lineEnd); dataOutputStream.writeBytes(parameterValue + lineEnd); } 

它工作得很好,所以我希望它有帮助。

对于像我这样挣扎的人来说,发送utf-8参数仍然没有运气……我遇到的问题是在dataOutputStream中,并将@RacZo的代码更改为下面的代码

 private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException { dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd); dataOutputStream.writeBytes("Content-Disposition: form-data; name=\""); dataOutputStream.write(parameterName.getBytes("UTF-8")); dataOutputStream.writeBytes(lineEnd); dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd); dataOutputStream.writeBytes(lineEnd); dataOutputStream.write(parameterValue.getBytes("UTF-8")); dataOutputStream.writeBytes(lineEnd); } 

希望为像我这样的人工作