Cara mengirim POST "multipart / form-data" di Android dengan Volley

89

Adakah yang bisa menyelesaikan pengiriman multipart/form-dataPOST di Android dengan Volley? Saya tidak berhasil mengupload image/pngmenggunakan permintaan POST ke server kami dan saya ingin tahu apakah ada yang melakukannya.

Saya percaya cara default untuk melakukan ini adalah dengan menimpa public byte[] getPostBody()di Request.javakelas dan melampirkan di Filesana dengan kunci Header kosong untuk batasnya. Namun, mengonversi file saya menjadi Stringuntuk Map<String, String> postParamsdan kemudian mengkodekannya lagi tampaknya membosankan dan tidak terlalu elegan. Juga saya tidak berhasil dalam upaya saya. Ini benar-benar satu-satunya hal yang menahan kami untuk beralih ke perpustakaan ini.

Bagaimanapun, semua pemikiran dan jawaban sangat dihargai. Terima kasih untuk bantuannya.

AllDayAmazing
sumber

Jawaban:

75

Saya mungkin salah dalam hal ini tetapi saya pikir Anda perlu menerapkannya sendiri com.android.volley.toolbox.HttpStackuntuk ini karena yang default ( HurlStackjika versi> Gingerbread atau HttpClientStack) tidak menangani multipart/form-data.

Edit:

Dan memang saya salah. Saya bisa melakukannya dengan menggunakan MultipartEntityRequest seperti ini:

public class MultipartRequest extends Request<String> {

    private MultipartEntity entity = new MultipartEntity();

    private static final String FILE_PART_NAME = "file";
    private static final String STRING_PART_NAME = "text";

    private final Response.Listener<String> mListener;
    private final File mFilePart;
    private final String mStringPart;

    public MultipartRequest(String url, Response.ErrorListener errorListener, Response.Listener<String> listener, File file, String stringPart)
    {
        super(Method.POST, url, errorListener);

        mListener = listener;
        mFilePart = file;
        mStringPart = stringPart;
        buildMultipartEntity();
    }

    private void buildMultipartEntity()
    {
        entity.addPart(FILE_PART_NAME, new FileBody(mFilePart));
        try
        {
            entity.addPart(STRING_PART_NAME, new StringBody(mStringPart));
        }
        catch (UnsupportedEncodingException e)
        {
            VolleyLog.e("UnsupportedEncodingException");
        }
    }

    @Override
    public String getBodyContentType()
    {
        return entity.getContentType().getValue();
    }

    @Override
    public byte[] getBody() throws AuthFailureError
    {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try
        {
            entity.writeTo(bos);
        }
        catch (IOException e)
        {
            VolleyLog.e("IOException writing to ByteArrayOutputStream");
        }
        return bos.toByteArray();
    }

    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response)
    {
        return Response.success("Uploaded", getCacheEntry());
    }

    @Override
    protected void deliverResponse(String response)
    {
        mListener.onResponse(response);
    }
}

Ini cukup mentah tetapi saya mencobanya dengan gambar dan string sederhana dan berhasil. Responsnya adalah placeholder, tidak masuk akal untuk mengembalikan String Respons dalam kasus ini. Saya mengalami masalah dalam menggunakan httpmime apache untuk menggunakan MultipartEntity jadi saya menggunakan https://code.google.com/p/httpclientandroidlib/ tidak tahu apakah ada cara yang lebih baik. Semoga membantu.

Edit

Anda dapat menggunakan httpmime tanpa menggunakan httpclientandroidlib, satu-satunya dependensi adalah httpcore.

alex
sumber
2
@LOG_TAG: Ini tidak akan mendukung file besar. Juga tidak akan mendukung bilah kemajuan. Alasannya adalah itu akan menempatkan semua data dalam satu byte []. Untuk file besar, Anda ingin menggunakan InputStream, yang tampaknya tidak mungkin dilakukan dengan voli. Tetapi mereka (volley devs) juga mengatakan bahwa volley tidak dibuat untuk file besar.
Patrick Boos
9
@ alex dapatkah Anda menaruh beberapa kode bagaimana menggunakan MultipartRequest?
Krishna Shrestha
5
Saya mendapatkan kesalahan ini: java.lang.NoClassDefFoundError: org.apache.http.entity.ContentType
Milad
1
MultipartEntity menggunakan apache http. saya ingin melakukannya tanpa perpustakaan multipart Apache. bagaimana saya bisa melakukan ini.
JosephM
1
return entity.getContentType (). getValue (); Kesalahan
Volodymyr Kulyk
14

Seperti disebutkan dalam presentasi di I / O (sekitar 4:05), Volley "sangat buruk" untuk muatan besar. Seperti yang saya pahami, itu berarti tidak menggunakan Volley untuk menerima / mengirim file (besar). Melihat kode tampaknya bahkan tidak dirancang untuk menangani data formulir multi bagian (misalnya Request.java memiliki getBodyContentType () dengan hardcode "application / x-www-form-urlencoded"; HttpClientStack :: createHttpRequest () hanya dapat menangani byte [], dll ...). Mungkin Anda akan dapat membuat implementasi yang dapat menangani multipart tetapi Jika saya menjadi Anda, saya hanya akan menggunakan HttpClient secara langsung dengan MultipartEntity seperti:

    HttpPost req = new HttpPost(composeTargetUrl());
    MultipartEntity entity = new MultipartEntity();
    entity.addPart(POST_IMAGE_VAR_NAME, new FileBody(toUpload));
    try {
        entity.addPart(POST_SESSION_VAR_NAME, new StringBody(uploadSessionId));
    } catch (UnsupportedEncodingException e) {
        throw new RuntimeException(e);
    }
    req.setEntity(entity);

Anda mungkin membutuhkan HttpClient yang lebih baru (yaitu bukan built-in) atau bahkan lebih baik, gunakan Volley dengan HttpClient yang lebih baru

Ognyan
sumber
1
Terima kasih banyak atas bantuannya, blog Anda menunjukkan sesuatu yang tidak saya pikirkan. Saya akan mencoba saran Anda melalui tautan di atas jika saya tidak bisa mendapatkan solusi Alex untuk berfungsi. Bersulang!
AllDayAmazing
Halo @Ogre_BGR, Bisakah Anda memberikan contoh lengkap cara mengunggah gambar menggunakan kode snap Anda. Saya mencoba banyak sampel saja, tetapi mereka sangat tua dan saya tidak bisa membuatnya berfungsi. Terima kasih
Thiago
Multipart sekarang didukung. Lihat jawaban lain di halaman ini.
Martin Konecny
1
@MartinKonecny ​​tolong tautkan jawaban yang benar di komentar Anda sehingga pengguna lain dapat langsung ke sana
Ognyan
Bagaimana saya bisa menambahkan parameter lain bersama dengan format multi bagian dalam satu permintaan?
casillas
10

UPDATE 2015/08/26:

Jika Anda tidak ingin menggunakan HttpEntity yang tidak digunakan lagi, berikut adalah kode contoh kerja saya (diuji dengan 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];

                    // read file and write it into form...
                    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);
                    }

                    // send multipart form data necesssary after file data...
                    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) {
        // 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);
    }
}

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

AKHIR UPDATE

Ini adalah kode contoh kerja saya (hanya diuji dengan file berukuran kecil):

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

            // Add binary body
            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>
BNK
sumber
3
Beberapa server SANGAT pilih-pilih. Jika Anda mengalami masalah, tambahkan SPASI antara ";" dan "filename =" saat membuat Content-Disposition dan "multipart / form-data; boundary =" + boundary;
Kevin
Terima kasih atas komentar Anda @Kevin. Sebenarnya, saya belum punya banyak aplikasi server untuk memeriksanya :-)
BNK
@HemsLodha: tolong lihat jawaban RacZo di pertanyaan saya berikut stackoverflow.com/questions/32240177/… untuk melihat apakah itu dapat membantu Anda atau tidak :)
BNK
1
Saya mengirim permintaan post multipart dengan volley dan akhirnya mengatur parameter ke url dan berhasil. Terima kasih atas bantuan @BNK.
JosephM
@ user3561494 tidak disarankan untuk file berukuran besar seperti video
BNK
9

Selesaikan Permintaan Multibagian dengan Kemajuan Unggahan

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;
import com.beusoft.app.AppContext;

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();
            // fuck it, 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);
            }
        }

    }
}

Penggunaan Sampel

protected <T> void uploadFile(final String tag, final String url,
            final File file, final String partName,         
            final Map<String, String> headerParams,
            final Response.Listener<String> resultDelivery,
            final Response.ErrorListener errorListener,
            MultipartProgressListener progListener) {
        AZNetworkRetryPolicy retryPolicy = new AZNetworkRetryPolicy();

        MultipartRequest mr = new MultipartRequest(url, errorListener,
                resultDelivery, file, file.length(), null, headerParams,
                partName, progListener);

        mr.setRetryPolicy(retryPolicy);
        mr.setTag(tag);

        Volley.newRequestQueue(this).add(mr);

    }
AZ_
sumber
Hai @AZ_ - saya mencoba kode Anda: Tapi saya mendapatkan kesalahan ini: MultipartRequest.getBody: IOException menulis ke ByteArrayOutputStream. Bisakah Anda membantu
Thiago
Saya tidak memiliki kode Anda, saya tidak bisa menyarankan apa pun yang lebih baik untuk membuka pertanyaan lain, alasan yang paling mungkin adalah Anda kehabisan memori virtual.
AZ_
1
Saya memiliki Pertanyaan Terbuka Saya baru: stackoverflow.com/questions/31474585/… Bisakah Anda membantu. terima kasih
Thiago
Bagaimana saya bisa menambahkan parameter lain bersama dengan format multi bagian dalam satu permintaan?
casillas
@casillas menambahkan pasangan nilai kunci ke header permintaan.
AZ_
8

Pendekatan yang sangat sederhana untuk dev yang hanya ingin mengirim parameter POST dalam permintaan multi bagian.

Lakukan perubahan berikut di kelas yang memperluas Request.java

Pertama tentukan konstanta ini:

String BOUNDARY = "s2retfgsGSRFsERFGHfgdfgw734yhFHW567TYHSrf4yarg"; //This the boundary which is used by the server to split the post parameters.
String MULTIPART_FORMDATA = "multipart/form-data;boundary=" + BOUNDARY;

Tambahkan fungsi pembantu untuk membuat badan postingan untuk Anda:

private String createPostBody(Map<String, String> params) {
        StringBuilder sbPost = new StringBuilder();
        if (params != null) {
            for (String key : params.keySet()) {
                if (params.get(key) != null) {
                    sbPost.append("\r\n" + "--" + BOUNDARY + "\r\n");
                    sbPost.append("Content-Disposition: form-data; name=\"" + key + "\"" + "\r\n\r\n");
                    sbPost.append(params.get(key).toString());
                }
            }
        }
        return sbPost.toString();
    } 

Ganti getBody () dan getBodyContentType

public String getBodyContentType() {
    return MULTIPART_FORMDATA;
}

public byte[] getBody() throws AuthFailureError {
        return createPostBody(getParams()).getBytes();
}
Arpit Ratan
sumber
1
Sangat sederhana dan bekerja dengan sempurna! Saya harus melakukannya sbPost.append("--" + BOUNDARY + "--");sebelum saya kembali karena API yang saya gunakan memerlukan tag penutup
Sirene
1
Terima kasih banyak :)
Arpit Ratan
Terima kasih! Ini berfungsi untuk saya di front-end tetapi back-end khususnya nodejs mengalami masalah saat menguraikannya? Apakah Anda mengalami semua itu?
Woppi
1
Maaf, saya tidak memiliki pengalaman backend :(
Arpit Ratan
@Arpit terima kasih, saya dapat menyelesaikan masalah saya dengan menggunakan kelas pembantu ini sebagai gantinya gist.github.com/anggadarkprince/…
Woppi
4

Jawaban pertama di SO.

Saya mengalami masalah yang sama dan menemukan kode @alex sangat membantu. Saya telah membuat beberapa modifikasi sederhana untuk mengirimkan sebanyak mungkin parameter yang diperlukan melalui HashMap, dan pada dasarnya menyalin parseNetworkResponse()dari StringRequest. Saya telah mencari secara online dan sangat terkejut menemukan bahwa tugas umum seperti itu jarang dijawab. Bagaimanapun, saya berharap kode dapat membantu:

public class MultipartRequest extends Request<String> {

private MultipartEntity entity = new MultipartEntity();

private static final String FILE_PART_NAME = "image";

private final Response.Listener<String> mListener;
private final File file;
private final HashMap<String, String> params;

public MultipartRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener, File file, HashMap<String, String> params)
{
    super(Method.POST, url, errorListener);

    mListener = listener;
    this.file = file;
    this.params = params;
    buildMultipartEntity();
}

private void buildMultipartEntity()
{
    entity.addPart(FILE_PART_NAME, new FileBody(file));
    try
    {
        for ( String key : params.keySet() ) {
            entity.addPart(key, new StringBody(params.get(key)));
        }
    }
    catch (UnsupportedEncodingException e)
    {
        VolleyLog.e("UnsupportedEncodingException");
    }
}

@Override
public String getBodyContentType()
{
    return entity.getContentType().getValue();
}

@Override
public byte[] getBody() throws AuthFailureError
{
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try
    {
        entity.writeTo(bos);
    }
    catch (IOException e)
    {
        VolleyLog.e("IOException writing to ByteArrayOutputStream");
    }
    return bos.toByteArray();
}

/**
 * copied from Android StringRequest class
 */
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
    String parsed;
    try {
        parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
    } catch (UnsupportedEncodingException e) {
        parsed = new String(response.data);
    }
    return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}

@Override
protected void deliverResponse(String response)
{
    mListener.onResponse(response);
}

Dan Anda dapat menggunakan kelas sebagai berikut:

    HashMap<String, String> params = new HashMap<String, String>();

    params.put("type", "Some Param");
    params.put("location", "Some Param");
    params.put("contact",  "Some Param");


    MultipartRequest mr = new MultipartRequest(url, new Response.Listener<String>(){

        @Override
        public void onResponse(String response) {
            Log.d("response", response);
        }

    }, new Response.ErrorListener(){

        @Override
        public void onErrorResponse(VolleyError error) {
            Log.e("Volley Request Error", error.getLocalizedMessage());
        }

    }, f, params);

    Volley.newRequestQueue(this).add(mr);
Michael Shang
sumber
0

Solusi lain, sangat ringan dengan kinerja tinggi dengan muatan besar:

Pustaka Klien Http Asinkron Android: http://loopj.com/android-async-http/

private static AsyncHttpClient client = new AsyncHttpClient();

private void uploadFileExecute(File file) {

    RequestParams params = new RequestParams();

    try { params.put("photo", file); } catch (FileNotFoundException e) {}

    client.post(getUrl(), params,

        new AsyncHttpResponseHandler() {

            public void onSuccess(String result) {

                Log.d(TAG,"uploadFile response: "+result);

            };

            public void onFailure(Throwable arg0, String errorMsg) {

                Log.d(TAG,"uploadFile ERROR!");

            };

        }

    );

}
Hpsaturn
sumber
2
ukuran file besar memberikan pengecualian memori
Ravi
1
@Ravi +1 perpustakaan ini menyebalkan untuk mengunggah file besar
Anton
jika Anda ingin mengirim file besar gunakan pustaka apache mime untuk multi bagian dan kemudian posting menggunakan pustaka ini.
Ravi
Anda perlu mengompres ukuran gambar dan kemudian menggunakan perpustakaan ini untuk mengunggah gambar Saya menemukan solusi dari URL di bawah ini: programmerguru.com/android-tutorial/… Saya harap ini dapat menghemat waktu seseorang.
Milan Sheth
@Ravi apache mime akan memberi Anda konflik dan kesalahan kelas duplikat.
Muhammad Saqib
0

Berikut adalah Solusi Sederhana Dan Contoh Lengkap untuk Mengupload File Menggunakan Android Volley

1) Impor Gradle

compile 'dev.dworks.libs:volleyplus:+'

2) Sekarang Buat RequestManager Kelas

public class RequestManager {
    private static RequestManager mRequestManager;
    /**
     * Queue which Manages the Network Requests :-)
     */
    private static RequestQueue mRequestQueue;
    // ImageLoader Instance

    private RequestManager() {

    }

    public static RequestManager get(Context context) {

        if (mRequestManager == null)
            mRequestManager = new RequestManager();

        return mRequestManager;
    }

    /**
     * @param context application context
     */
    public static RequestQueue getnstance(Context context) {

        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(context);
        }

        return mRequestQueue;

    }


}

3) Sekarang Buat Kelas untuk menangani Permintaan untuk mengunggah File WebService

public class WebService {
    private RequestQueue mRequestQueue;
    private static WebService apiRequests = null;

    public static WebService getInstance() {
        if (apiRequests == null) {
            apiRequests = new WebService();
            return apiRequests;
        }
        return apiRequests;
    }
    public void updateProfile(Context context, String doc_name, String doc_type, String appliance_id, File file, Response.Listener<String> listener, Response.ErrorListener errorListener) {
        SimpleMultiPartRequest request = new SimpleMultiPartRequest(Request.Method.POST, "YOUR URL HERE", listener, errorListener);
//        request.setParams(data);
        mRequestQueue = RequestManager.getnstance(context);
        request.addMultipartParam("token", "text", "tdfysghfhsdfh");
        request.addMultipartParam("parameter_1", "text", doc_name);
        request.addMultipartParam("dparameter_2", "text", doc_type);
        request.addMultipartParam("parameter_3", "text", appliance_id);
            request.addFile("document_file", file.getPath());

        request.setFixedStreamingMode(true);
        mRequestQueue.add(request);
    }
}

4) Dan Sekarang Panggil Metode Seperti Ini ke Layanan

public class Main2Activity extends AppCompatActivity implements Response.ErrorListener, Response.Listener<String>{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        Button button=(Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                uploadData();
            }
        });
    }

    private void uploadData() {
        WebService.getInstance().updateProfile(getActivity(), "appl_doc", "appliance", "1", mChoosenFile, this, this);
    }

    @Override
    public void onErrorResponse(VolleyError error) {

    }

    @Override
    public void onResponse(String response) {
     //Your response here 
    }
}
Cepat Belajar
sumber
Saya mendapatkan kesalahan ini dengan solusi Anda: java.lang.NoSuchMethodError: Tidak ada metode langsung <init> (ILjava / lang / String; Lcom / android / volley / Request $ Priority; Lcom / android / volley / Response $ ErrorListener; Lcom / android / volley / RetryPolicy;) V di kelas Lcom / android / volley / Request; atau kelas supernya (deklarasi 'com.android.volley.Request' muncul di /data/data/com.footballscout.app/files/instant-run/dex/slice-slice_4-classes.dex)
SpyZip
apakah Anda memeriksa gradle dan impor yang benar di kelas?
Pelajar cepat
Saya menggunakan yang pernah dijelaskan di sini dan jawaban Anda github.com/DWorkS/VolleyPlus
SpyZip
1
dan periksa impor Anda di kelas mana pun yang Anda gunakan karena Anda tidak boleh menggunakan impor yang benar untuk volley seperti kesalahan menunjuk pada pendengar kesalahan, periksa impor lagi dan gradle kemudian bersihkan proyek, terima kasih, jika Anda masih menemukan masalah jangan beri tahu saya
Pelajar cepat
-1

Ini adalah cara saya melakukannya. Mungkin bermanfaat bagi orang lain:

private void updateType(){
    // Log.i(TAG,"updateType");
     StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {

         @Override
         public void onResponse(String response) {
             // running on main thread-------
             try {
                 JSONObject res = new JSONObject(response);
                 res.getString("result");
                 System.out.println("Response:" + res.getString("result"));

                 }else{
                     CustomTast ct=new CustomTast(context);
                     ct.showCustomAlert("Network/Server Disconnected",R.drawable.disconnect);
                 }

             } catch (Exception e) {
                 e.printStackTrace();

                 //Log.e("Response", "==> " + e.getMessage());
             }
         }
     }, new Response.ErrorListener() {
         @Override
         public void onErrorResponse(VolleyError volleyError) {
             // running on main thread-------
             VolleyLog.d(TAG, "Error: " + volleyError.getMessage());

         }
     }) {
         protected Map<String, String> getParams() {
             HashMap<String, String> hashMapParams = new HashMap<String, String>();
             hashMapParams.put("key", "value");
             hashMapParams.put("key", "value");
             hashMapParams.put("key", "value"));
             hashMapParams.put("key", "value");
             System.out.println("Hashmap:" + hashMapParams);
             return hashMapParams;
         }
     };
     AppController.getInstance().addToRequestQueue(request);

 }
koteswara DK
sumber