Kishor Bikram Oli
Kishor Bikram Oli

Reputation: 1848

How to upload array of image files using MultiPart in Android Volley Library

I'm just beginner in Android App development.

I want to upload image files using Android Volley library.

I have used this helper class found somewhere in some blog.:

    public class VolleyMultiPartRequest extends Request<NetworkResponse> {

    private final String twoHyphens = "--";
    private final String lineEnd = "\r\n";
    private final String boundary = "apiclient-" + System.currentTimeMillis();

    private Response.Listener<NetworkResponse> mListener;
    private Response.ErrorListener mErrorListener;
    private Map<String, String> mHeaders;

    SharedPreferencesManager sharedPreferencesManager =null;

    public VolleyMultiPartRequest(int method, String url,
                                  Response.Listener<NetworkResponse> listener,
                                  Response.ErrorListener errorListener, Context context) {
        super(method, url, errorListener);
        this.mListener = listener;
        this.mErrorListener = errorListener;
        this.sharedPreferencesManager = new SharedPreferencesManager(context);
    }


   @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = new HashMap<String, String>();
        headers.put("Accept", "application/json");
        headers.put("Authorization", "Bearer " + sharedPreferencesManager.retreiveString(AppText.ACCESS_TOKEN));
        headers.put("Content-Type", "multipart/form-data");
        return headers;
    }
    @Override
    public String getBodyContentType() {
        return "multipart/form-data;boundary=" + boundary;
    }

    @Override
    public byte[] getBody() throws AuthFailureError {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(bos);

        try {
            // populate text payload
            Map<String, String> params = getParams();
            if (params != null && params.size() > 0) {
                textParse(dos, params, getParamsEncoding());
            }

            // populate data byte payload
            Map<String, DataPart> data = getByteData();
            if (data != null && data.size() > 0) {
                dataParse(dos, data);
            }

            // close multipart form data after text and file data
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

            return bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    protected Map<String, DataPart> getByteData() throws AuthFailureError {
        return null;
    }

    @Override
    protected Response<NetworkResponse> 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);
    }


    private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException {
        try {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
            }
        } catch (UnsupportedEncodingException uee) {
            throw new RuntimeException("Encoding not supported: " + encoding, uee);
        }
    }


    private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException {
        for (Map.Entry<String, DataPart> entry : data.entrySet()) {
            buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
        }
    }


    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(lineEnd);
        dataOutputStream.writeBytes(parameterValue + lineEnd);
    }

    private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
        dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
        dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
                inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd);
        if (dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) {
            dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd);
        }
        dataOutputStream.writeBytes(lineEnd);

        ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
        int bytesAvailable = fileInputStream.available();

        int maxBufferSize = 1024 * 1024;
        int bufferSize = Math.min(bytesAvailable, maxBufferSize);
        byte[] buffer = new byte[bufferSize];

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

    public class DataPart {
        private String fileName;
        private byte[] content;
        private String type;

        public DataPart() {
        }

        public DataPart(String name, byte[] data) {
            fileName = name;
            content = data;
        }

        String getFileName() {
            return fileName;
        }

        byte[] getContent() {
            return content;
        }

        String getType() {
            return type;
        }

    }
}

And called this helper like this:

 VolleyMultiPartRequest volleyMultipartRequest = new VolleyMultiPartRequest(Request.Method.POST, Api.UPLOAD_FILE,
                new Response.Listener<NetworkResponse>() {
                    @Override
                    public void onResponse(NetworkResponse response) {
                        try {
                            JSONObject obj = new JSONObject(new String(response.data));
                            Toast.makeText(context, obj.getString("message"), Toast.LENGTH_SHORT).show();
                            successCallBack.onSuccess(obj);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Toast.makeText(context, error.getMessage(), Toast.LENGTH_SHORT).show();
                        try {
                            errorCallBack.onError(new JSONObject(""));
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                }, context) {

            /*
            * If you want to add more parameters with the image
            * you can do it here
            * here we have only one parameter with the image
            * which is tags
            * */
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String, String> params = new HashMap<>();
                params.put("file_for", "post");
                params.put("file_type", "image");
                return params;
            }

            /*
            * Here we are passing image by renaming it with a unique name
            * */
            @Override
            protected Map<String, DataPart> getByteData() {
                Map<String, DataPart> params = new HashMap<>();
                long imagename = System.currentTimeMillis();
                params.put("images[]", new DataPart(imagename + ".png", getFileDataFromDrawable(bitmap)));
                return params;
            }


        };

I'm getting server error as a response.

I tried different tutorials but didn't find the exact way and easy solution.

In the postman, headers and params are like this, there are an array of images, you can see in photos attached (8 photos). I want to do exact same API call using volley library.

enter image description here enter image description here

Upvotes: 1

Views: 4221

Answers (2)

Shruthi Holla
Shruthi Holla

Reputation: 20

Just replace getByteData() method with this below code:

private dataPartList = ArrayList();

@Override
protected Map<String, List<DataPart>> getByteDataList(){
 Map<String, List<DataPart>> params = new HashMap<>();
  params.put("yourKey","dataPartList");
    return params
}

Upvotes: -1

Ramesh sambu
Ramesh sambu

Reputation: 3539

Try this code:

I had similar kind of issue i fixed using this

Uploading multiple files in array using multipart

  1. Add dependecies

    compile 'org.apache.httpcomponents:httpcore:4.2.4'
    compile 'org.apache.httpcomponents:httpmime:4.2'
    compile 'com.mcxiaoke.volley:library:1.0.19'
    

2.Add in gradle

    defaultConfig {
            useLibrary 'org.apache.http.legacy'

    }
  1. Helper class AndroidMultiPartEntity.java

    public class AndroidMultiPartEntity extends MultipartEntity
    
    {
    
        private final ProgressListener listener;
    
        public AndroidMultiPartEntity(final ProgressListener listener) {
            super();
            this.listener = listener;
        }
    
        public AndroidMultiPartEntity(final HttpMultipartMode mode, final ProgressListener listener) {
            super(mode);
            this.listener = listener;
        }
    
        public AndroidMultiPartEntity(HttpMultipartMode mode, final String boundary,
                                      final Charset charset, final ProgressListener listener) {
            super(mode, boundary, charset);
            this.listener = listener;
        }
    
        @Override
        public void writeTo(final OutputStream outstream) throws IOException {
            super.writeTo(new CountingOutputStream(outstream, this.listener));
        }
    
        public interface ProgressListener {
            void transferred(long num);
        }
    
        public static class CountingOutputStream extends FilterOutputStream {
    
            private final ProgressListener listener;
            private long transferred;
    
            public CountingOutputStream(final OutputStream out,
                                        final ProgressListener listener) {
                super(out);
                this.listener = listener;
                this.transferred = 0;
            }
    
            public void write(byte[] b, int off, int len) throws IOException {
                out.write(b, off, len);
                this.transferred += len;
                this.listener.transferred(this.transferred);
            }
    
            public void write(int b) throws IOException {
                out.write(b);
                this.transferred++;
                this.listener.transferred(this.transferred);
            }
        }
    }
    
  2. API call method

    private class registerCall extends AsyncTask<Void, Integer, String> {
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    
    @Override
    protected void onProgressUpdate(Integer... progress) {
    }
    
    @Override
    protected String doInBackground(Void... params) {
        return registerMultipartCall();
    }
    
    private String registerMultipartCall() {
        String responseString = null;
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost("URL");  //UPLOAD URL
        try {
            AndroidMultiPartEntity entity = new AndroidMultiPartEntity(new AndroidMultiPartEntity.ProgressListener() {
                @Override
                public void transferred(long num) {
                }
            });
    
            File sourceFile = new File(filePath);
            File sourceFile2 = new File(filePath);
    
            entity.addPart("images[0]",  new FileBody(sourceFile));
            entity.addPart("images[1]",  new FileBody(sourceFile2));
            //Do your stuff multiple files
    
            entity.addPart("file_type", new StringBody("image");
            entity.addPart("file_form", new StringBody("post");
    
            httppost.addHeader("Accept","application/json");
            httppost.addHeader("Content-Type", "multipart/form-data");
            httppost.addHeader("Authorization", "Bearer " + sharedPreferencesManager.retreiveString(AppText.ACCESS_TOKEN));
    
    
            httppost.setEntity(entity);
    
            // Making server call
            HttpResponse response = httpclient.execute(httppost);
            HttpEntity r_entity = response.getEntity();
    
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 200) {
                // Server response
                statusCode = 200;
                responseString = EntityUtils.toString(r_entity);
            } else {
                statusCode = 200;
                responseString = "Error occurred! Http Status Code: " + statusCode;
            }
    
        } catch (ClientProtocolException e) {
            responseString = e.toString();
        } catch (IOException e) {
            responseString = e.toString();
        }
    
        return responseString;
    
    }
    
    @Override
    protected void onPostExecute(String result) {
        hideProgressDialog();
    
    }
    

    }

5.Calling Async

  new registerCall().execute();

Upvotes: 4

Related Questions