I am using Volley for my API call. I need to post a image to my sever.
I have tried many MultipartRequest implementation, None works.
I just tried using a sample from How to send a “multipart/form-data” POST in Android with Volley by AZ_.
But I get MultipartRequest.getBody: IOException writing to ByteArrayOutputStream Error.
Can you help me out on my code, or know any complete sample for uploading a image using Volley please. Thank you.
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.util.CharsetUtils;
import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyLog;
//Code by:
//https://mcmap.net/q/89355/-how-to-send-a-multipart-form-data-post-in-android-with-volley
//AZ_
//
/**
* Problems : E/Volley﹕ [17225] MultipartRequest.getBody: IOException writing to ByteArrayOutputStream
*/
public class MultipartRequest extends Request<String> {
MultipartEntityBuilder entity = MultipartEntityBuilder.create();
HttpEntity httpentity;
private String FILE_PART_NAME = "files";
private final Response.Listener<String> mListener;
private final File mFilePart;
private final Map<String, String> mStringPart;
private Map<String, String> headerParams;
private final MultipartProgressListener multipartProgressListener;
private long fileLength = 0L;
public MultipartRequest(String url, Response.ErrorListener errorListener,
Response.Listener<String> listener, File file, long fileLength,
Map<String, String> mStringPart,
final Map<String, String> headerParams, String partName,
MultipartProgressListener progLitener) {
super(Method.POST, url, errorListener);
this.mListener = listener;
this.mFilePart = file;
this.fileLength = fileLength;
this.mStringPart = mStringPart;
this.headerParams = headerParams;
this.FILE_PART_NAME = partName;
this.multipartProgressListener = progLitener;
entity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
try {
entity.setCharset(CharsetUtils.get("UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
buildMultipartEntity();
httpentity = entity.build();
}
// public void addStringBody(String param, String value) {
// if (mStringPart != null) {
// mStringPart.put(param, value);
// }
// }
private void buildMultipartEntity() {
entity.addPart(FILE_PART_NAME, new FileBody(mFilePart, ContentType.create("image/gif"), mFilePart.getName()));
if (mStringPart != null) {
for (Map.Entry<String, String> entry : mStringPart.entrySet()) {
entity.addTextBody(entry.getKey(), entry.getValue());
}
}
}
@Override
public String getBodyContentType() {
return httpentity.getContentType().getValue();
}
@Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
httpentity.writeTo(new CountingOutputStream(bos, fileLength, multipartProgressListener));
}
catch (IOException e) {
VolleyLog.e("IOException writing to ByteArrayOutputStream");
}
return bos.toByteArray();
}
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
try {
// System.out.println("Network Response "+ new String(response.data, "UTF-8"));
return Response.success(new String(response.data, "UTF-8"),
getCacheEntry());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
// it should never happen though
return Response.success(new String(response.data), getCacheEntry());
}
}
@Override
protected void deliverResponse(String response) {
mListener.onResponse(response);
}
//Override getHeaders() if you want to put anything in header
public static interface MultipartProgressListener {
void transferred(long transfered, int progress);
}
public static class CountingOutputStream extends FilterOutputStream {
private final MultipartProgressListener progListener;
private long transferred;
private long fileLength;
public CountingOutputStream(final OutputStream out, long fileLength,
final MultipartProgressListener listener) {
super(out);
this.fileLength = fileLength;
this.progListener = listener;
this.transferred = 0;
}
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
if (progListener != null) {
this.transferred += len;
int prog = (int) (transferred * 100 / fileLength);
this.progListener.transferred(this.transferred, prog);
}
}
public void write(int b) throws IOException {
out.write(b);
if (progListener != null) {
this.transferred++;
int prog = (int) (transferred * 100 / fileLength);
this.progListener.transferred(this.transferred, prog);
}
}
}
}
User API Class
public void uploadFile(String api, File file, long fileLength, String partName, final UserUploadSuccessListener listener) {
this.listener = listener;
String url = Constant.DOMAIN + api;
Map<String, String> mHeaderParams = new HashMap<String, String>();
mHeaderParams.put("pram", "pramValue");
MultipartRequest multipartRequest = new MultipartRequest
(url, errorListener, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
listener.onUserUploadFile(response);
}
}, file, fileLength, null, mHeaderParams, partName, null);
multipartRequest.setRetryPolicy(new DefaultRetryPolicy(
30000, //30 seconds - change to what you want
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
mRequestQueue.add(multipartRequest);
}
Then Call it on MainActivity:
private void test1(){
File file = new File("path:/storage/emulated/0/copy_folder/Magazine/images/assets/images/img_0007.jpg");
long fileLength = file.length();
new UserApi().uploadFile("upload", file, fileLength, "imgPost", new UserApi.UserUploadSuccessListener() {
@Override
public void onUserUploadFile(String response) {
text.setText("uploadImage() - onUserUploadFile -> \n " + response.toString());
}
@Override
public void onError(VolleyError error) {
text.setText("uploadImage() - onError -> \n " + error.toString());
}
@Override
public void onResponseError(String message) {
text.setText("uploadImage() - onResponseError -> \n " + message);
}
});
}
Here are my dependencies in Android Studio:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.google.code.gson:gson:2.3'
compile 'com.mcxiaoke.volley:library:1.0.+'
compile('org.apache.httpcomponents:httpmime:4.3.6') {
exclude module: 'httpclient'
}
compile 'org.apache.httpcomponents:httpclient-android:4.3.5'
}