Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Volley: MultipartRequest.getBody: IOException writing to ByteArrayOutputStream

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://stackoverflow.com/questions/16797468/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'

}
like image 217
Thiago Avatar asked Jul 17 '15 11:07

Thiago


1 Answers

Have you found the solution yet? If not, you can have a read at my answer at How to send a “multipart/form-data” POST in Android with Volley . I use MultipartEntityBuilder to build the parts.

If don't wanna use HttpEntity because of deprecation, please take a look at my working solution Working POST Multipart Request with Volley and without HttpEntity.

Hope this helps!

like image 124
BNK Avatar answered Sep 20 '22 06:09

BNK