ACTUALIZACIÓN 26/08/2015:
Si no desea utilizar HttpEntity obsoleto, aquí está mi código de muestra de trabajo (probado con ASP.Net WebAPI)
MultipartActivity.java
package com.example.volleyapp;
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 com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.example.volleyapp.BaseVolleyRequest;
import com.example.volleyapp.VolleySingleton;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class MultipartActivity extends Activity {
final Context mContext = this;
String mimeType;
DataOutputStream dos = null;
String lineEnd = "\r\n";
String boundary = "apiclient-" + System.currentTimeMillis();
String twoHyphens = "--";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1024 * 1024;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_multipart);
Drawable drawable = ContextCompat.getDrawable(mContext, R.drawable.ic_action_file_attachment_light);
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
final byte[] bitmapData = byteArrayOutputStream.toByteArray();
String url = "http://192.168.1.100/api/postfile";
mimeType = "multipart/form-data;boundary=" + boundary;
BaseVolleyRequest baseVolleyRequest = new BaseVolleyRequest(1, url, new Response.Listener<NetworkResponse>() {
@Override
public void onResponse(NetworkResponse response) {
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
}) {
@Override
public String getBodyContentType() {
return mimeType;
}
@Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
dos = new DataOutputStream(bos);
try {
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"uploaded_file\";filename=\""
+ "ic_action_file_attachment_light.png" + "\"" + lineEnd);
dos.writeBytes(lineEnd);
ByteArrayInputStream fileInputStream = new ByteArrayInputStream(bitmapData);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return bitmapData;
}
};
VolleySingleton.getInstance(mContext).addToRequestQueue(baseVolleyRequest);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_multipart, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
BaseVolleyRequest.java:
package com.example.volleyapp;
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 com.google.gson.JsonSyntaxException;
public class BaseVolleyRequest extends Request<NetworkResponse> {
private final Response.Listener<NetworkResponse> mListener;
private final Response.ErrorListener mErrorListener;
public BaseVolleyRequest(String url, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) {
super(0, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
}
public BaseVolleyRequest(int method, String url, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
this.mErrorListener = errorListener;
}
@Override
protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {
try {
return Response.success(
response,
HttpHeaderParser.parseCacheHeaders(response));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
} catch (Exception e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(NetworkResponse response) {
mListener.onResponse(response);
}
@Override
protected VolleyError parseNetworkError(VolleyError volleyError) {
return super.parseNetworkError(volleyError);
}
@Override
public void deliverError(VolleyError error) {
mErrorListener.onErrorResponse(error);
}
}
FIN DE ACTUALIZACIÓN
Este es mi código de muestra de trabajo (solo probado con archivos de tamaño pequeño):
public class FileUploadActivity extends Activity {
private final Context mContext = this;
HttpEntity httpEntity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_upload);
Drawable drawable = getResources().getDrawable(R.drawable.ic_action_home);
if (drawable != null) {
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
final byte[] bitmapdata = stream.toByteArray();
String url = "http://10.0.2.2/api/fileupload";
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
if (bitmapdata != null) {
ContentType contentType = ContentType.create("image/png");
String fileName = "ic_action_home.png";
builder.addBinaryBody("file", bitmapdata, contentType, fileName);
httpEntity = builder.build();
MyRequest myRequest = new MyRequest(Request.Method.POST, url, new Response.Listener<NetworkResponse>() {
@Override
public void onResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
Toast.makeText(mContext, jsonString, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(mContext, error.toString(), Toast.LENGTH_SHORT).show();
}
}) {
@Override
public String getBodyContentType() {
return httpEntity.getContentType().getValue();
}
@Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
httpEntity.writeTo(bos);
} catch (IOException e) {
VolleyLog.e("IOException writing to ByteArrayOutputStream");
}
return bos.toByteArray();
}
};
MySingleton.getInstance(this).addToRequestQueue(myRequest);
}
}
}
...
}
public class MyRequest extends Request<NetworkResponse>