title: Working POST Multipart Request with Volley and without HttpEntity
body: <p>This is not really a question, however, I would like to share some of my working code here for your reference when you need.</p>
  
  <p>As we know that <code>HttpEntity</code> is deprecated from API22 and comletely removed since API23. At the moment, we cannot access <a href="http://developer.android.com/reference/org/apache/http/HttpEntity.html?is-external=true" rel="noreferrer">HttpEntity Reference on Android Developer</a> anymore (404).  So, the following is my working sample code for <strong>POST Multipart Request with Volley and without HttpEntity</strong>. It's working, tested with <code>Asp.Net Web API</code>. Of course, the code perhaps is just a basic sample that posts two existed drawable files, also is not the best solution for all cases, and not good tuning.</p>
  
  <p><strong>MultipartActivity.java:</strong></p>
  
  <pre><code>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&lt;NetworkResponse&gt;() {
              @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 &gt; 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();
      }
  }
  </code></pre>
  
  <p><strong>MultipartRequest.java:</strong></p>
  
  <pre><code>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&lt;NetworkResponse&gt; {
      private final Response.Listener&lt;NetworkResponse&gt; mListener;
      private final Response.ErrorListener mErrorListener;
      private final Map&lt;String, String&gt; mHeaders;
      private final String mMimeType;
      private final byte[] mMultipartBody;
  
      public MultipartRequest(String url, Map&lt;String, String&gt; headers, String mimeType, byte[] multipartBody, Response.Listener&lt;NetworkResponse&gt; 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&lt;String, String&gt; 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&lt;NetworkResponse&gt; 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);
      }
  }
  </code></pre>
  
  <p><strong>UPDATE:</strong></p>
  
  <p>For text part, please refer to @Oscar's answer below.</p>