Working POST Multipart Anfrage mit Volley und ohne HttpEntity

Das ist nicht wirklich eine Frage, aber ich würde gerne einige meiner Arbeitscode hier für Ihre Referenz teilen, wenn Sie brauchen.

Wie wir wissen, ist HttpEntity ab API22 veraltet und seit API23 vollständig entfernt. Im Moment können wir nicht mehr auf HttpEntity Reference auf Android Developer zugreifen (404). Also, das Folgende ist mein funktionierender Beispielcode für POST Multipart Request mit Volley und ohne HttpEntity . Es funktioniert, getestet mit Asp.Net Web API . Natürlich ist der Code vielleicht nur ein einfaches Beispiel, das zwei existierende, ausklappbare Dateien posten kann, es ist auch nicht die beste Lösung für alle Fälle und keine gute Abstimmung.

Irgendwelche Vorschläge für besseren / schöneren Code werden geschätzt.

Hoffe das hilft!

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() { @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 { private final Response.Listener mListener; private final Response.ErrorListener mErrorListener; private final Map mHeaders; private final String mMimeType; private final byte[] mMultipartBody; public MultipartRequest(String url, Map headers, String mimeType, byte[] multipartBody, Response.Listener 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 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 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); } } 

AKTUALISIEREN:

Für einen Textteil beziehen Sie sich bitte auf @ RacZos Antwort unten.

Ich schreibe deinen Code @RacZo und @BNK mehr modular und einfach zu verwenden wie

 VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, url, new Response.Listener() { @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 getParams() { Map 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 getByteData() { Map 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); 

Überprüfen Sie voller Code VolleyMultipartRequest in meinem core .

Schöne Antwort @BNK!

Ich möchte nur zur Antwort hinzufügen … Ich habe versucht, herauszufinden, wie man Textfelder an den Körper anfügt und erstellte die folgende function, um es zu tun:

 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); } 

Es funktioniert ziemlich gut, also hoffe ich, dass es hilft.

für diejenigen, die wie ich kämpfen, um utf-8 Parameter und immer noch kein Glück zu senden … das Problem, das ich hatte, war in der dataOutputStream, und ändern Sie den Code von @RacZo in den unteren Code

 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); } 

Ich hoffe, diese Arbeit für jemanden wie mich