Volley ile Android'de "multipart / form-data" POST'u nasıl gönderilir


89

multipart/form-dataHenüz Volley ile Android'de bir POST göndermeyi başaran oldu mu? image/pngSunucumuza bir POST isteği kullanarak yüklemeye çalışırken başarılı olamadım ve varsa merak ediyorum.

Ben geçersiz olacaktır Bunu yapmanın varsayılan yol inanıyoruz public byte[] getPostBody()içinde Request.javasınıf ve takmak Filesınır için boş Başlık anahtarla orada. Ancak, dosyamı bir Stringfor için dönüştürmek Map<String, String> postParamsve sonra tekrar kodlamak, kalın ve zarif görünmüyor. Ayrıca girişimlerimde başarısız oldum. Bu gerçekten bizi bu kütüphaneye geçmekten alıkoyan tek şey.

Her neyse, tüm düşünceler ve cevaplar son derece takdir ediliyor. Yardımın için teşekkürler.

Yanıtlar:


75

Bu konuda yanılıyor olabilirim, ancak bunun için kendinizinkini uygulamanız gerektiğini düşünüyorum com.android.volley.toolbox.HttpStackçünkü varsayılan olanlar ( HurlStackeğer sürüm> Gingerbread veya HttpClientStack) ilgilenmiyor multipart/form-data.

Düzenle:

Ve gerçekten yanılmışım. Bunu MultipartEntityİstek içinde şu şekilde yapabildim :

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

Oldukça ham ama bir görüntü ve basit bir dizeyle denedim ve işe yarıyor. Yanıt bir yer tutucudur, bu durumda bir Yanıt Dizesi döndürmenin pek bir anlamı yoktur. MultipartEntity'yi kullanmak için apache httpmime'ı kullanırken sorunlar yaşadım, bu yüzden bunu kullandım https://code.google.com/p/httpclientandroidlib/ daha iyi bir yol olup olmadığını bilmiyorum. Umarım yardımcı olur.

Düzenle

Httpmime'yi httpclientandroidlib kullanmadan kullanabilirsiniz, tek bağımlılık httpcore'dur.


2
@LOG_TAG: Bu, büyük dosyaları desteklemez. Bir ilerleme çubuğunu da desteklemeyecektir. Nedeni, tüm verileri tek bir bayta [] koymasıdır. Büyük dosyalar için, voleybolda mümkün görünmeyen bir InputStream kullanmak istiyorsunuz. Ama onlar (voleybol geliştiricileri) voleybolun büyük dosyalar için yapılmadığını da söylüyorlar.
Patrick Boos

9
@alex, MultipartRequest'i nasıl kullanacağınıza biraz kod koyabilir misiniz?
Krishna Shrestha

5
Bu hatayı alıyorum: java.lang.NoClassDefFoundError: org.apache.http.entity.ContentType
Milad

1
Apache http kullanarak MultipartEntity. apache çok parçalı kitaplık olmadan yapmak istiyorum. bunu nasıl yapabilirim.
JosephM

1
return entity.getContentType (). getValue (); Hata
Volodymyr Kulyk

14

I / O'daki sunumda da belirtildiği gibi (yaklaşık 4:05), Voleybol büyük yükler için "korkunçtur". Anladığım kadarıyla bu, (büyük) dosyaları almak / göndermek için Volley kullanmamak anlamına geliyor. Koda bakıldığında, çok parçalı form verilerini işlemek için tasarlanmamış gibi görünüyor (örneğin, Request.java sabit kodlu "application / x-www-form-urlencoded" ile getBodyContentType () 'a sahip; HttpClientStack :: createHttpRequest () yalnızca baytı işleyebilir [], vb...). Muhtemelen çok parçalı işleyebilen uygulama yaratabileceksiniz, ancak yerinde olsaydım HttpClient'i doğrudan MultipartEntity ile kullanacağım:

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

Daha yeni HttpClient'e (yani yerleşik değil) ihtiyacınız olabilir veya daha iyisi, Volley'i daha yeni HttpClient ile kullanın


1
Yardımın için çok teşekkürler, blogunuz bana aklıma gelmeyen bir şey gösteriyor. Alex'in çözümünü çalıştıramazsam, önerinizi yukarıdaki bağlantı üzerinden deneyeceğim. Şerefe!
AllDayAmazing

Merhaba @Ogre_BGR, Snap kodunu kullanarak bir görüntünün nasıl yükleneceği konusunda tam bir örnek verebilir misiniz? Sadece birçok örneği denedim, ancak çok eski ve işe yarayamıyorum. Teşekkür ederim
Thiago

Multipart artık desteklenmektedir. Bu sayfadaki diğer cevaplara bakın.
Martin Konecny

1
Diğer kullanıcıların bu doğrudan gitmek böylece @MartinKonecny yorumunuzda doğru cevabı link veriniz
Ognyan

Tek bir istekte çok parçalı formatın yanı sıra diğer parametreleri nasıl ekleyebilirim?
casillas

10

GÜNCELLEME 2015/08/26:

Kullanımdan kaldırılmış HttpEntity'yi kullanmak istemiyorsanız işte örnek kodum (ASP.Net WebAPI ile test edilmiştir)

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

GÜNCELLEMENİN SONU

Bu benim çalışan örnek kodum (yalnızca küçük boyutlu dosyalarla test edildi):

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>

3
Bazı sunucular ÇOK seçicidir. Sorun yaşıyorsanız ";" arasına bir BOŞLUK ekleyin. ve Content-Disposition ve "multipart / form-data; boundary =" + borderary oluştururken "filename =";
Kevin

Yorumunuz için teşekkürler @Kevin. Aslında, bunu kontrol etmek için çok fazla sunucu uygulamam yok :-)
BNK

@HemsLodha: Lütfen RacZo'nun size yardımcı olup olamayacağını görmek için aşağıdaki soru stackoverflow.com/questions/32240177/… adresindeki RacZo'nun cevabına bir göz atın :)
BNK

1
Volley ile çok parçalı istek gönderiyorum ve sonunda parametreyi url olarak ayarlıyorum ve çalışıyor. Yardım için teşekkürler @BNK.
JosephM

@ user3561494 video gibi büyük boyutlu dosyalar için önerilmez
BNK

9

Yükleme İlerlemesiyle Çok Parçalı İsteği Tamamlayın

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

    }
}

Örnek Kullanım

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

    }

Merhaba @AZ_ - kodunuzu denedim: Ama şu hatayı alıyorum: MultipartRequest.getBody: IOException ByteArrayOutputStream'e yazıyor. Lütfen yardım eder misin
Thiago

Kodunuz bende yok, başka bir soruyu açmak için daha iyi bir şey öneremem, en olası sebep sanal belleğinizin bitmiş olması olabilir.
AZ_

1
Açık I yeni Soru var: stackoverflow.com/questions/31474585/… Yardımcı olabilir misiniz lütfen? teşekkür ederim
Thiago

Tek bir istekte çok parçalı formatın yanı sıra diğer parametreleri nasıl ekleyebilirim?
casillas

@casillas, isteğin başlığına anahtar değer çifti ekler.
AZ_

8

Çok parçalı istekte POST parametreleri göndermek isteyen geliştiriciler için çok basit bir yaklaşım.

Request.java'yı genişleten sınıfta aşağıdaki değişiklikleri yapın

Önce şu sabitleri tanımlayın:

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;

Sizin için bir gönderi gövdesi oluşturmak için bir yardımcı işlev ekleyin:

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

GetBody () ve getBodyContentType öğelerini geçersiz kılın

public String getBodyContentType() {
    return MULTIPART_FORMDATA;
}

public byte[] getBody() throws AuthFailureError {
        return createPostBody(getParams()).getBytes();
}

1
Çok basit ve mükemmel çalışıyor! Ben gerekiyordu sbPost.append("--" + BOUNDARY + "--");ben kullanıyorum API bir kapanış etiketi gerektirir beri dönmeden önce sağ
Sirenler

Teşekkürler! Bu, ön uçta benim için çalıştı, ancak arka uç özellikle nodejs, onu ayrıştırmada sorun mu yaşıyor? Bunlardan herhangi birini yaşadın mı?
Woppi

1
Maalesef arka uç deneyimim yok :(
Arpit Ratan

@Arpit teşekkürler, bunun yerine bu yardımcı sınıf kullanarak benim sorunu çözmek için başardı gist.github.com/anggadarkprince/...
Woppi

Basit ve kullanışlı. Bu yaklaşımı paylaştığınız için teşekkürler!
lgallard

4

SO ile ilgili ilk cevap.

Aynı sorunla karşılaştım ve @alex'in kodunu çok yararlı buldum. HashMap aracılığıyla gerektiği kadar çok parametreyi geçirmek için bazı basit değişiklikler yaptım ve temelde parseNetworkResponse()StringRequest'ten kopyaladım . İnternette araştırma yaptım ve böylesine yaygın bir görevin nadiren yanıtlandığını öğrendiğimde çok şaşırdım. Her neyse, kodun yardımcı olmasını diliyorum:

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

Ve sınıfı aşağıdaki gibi kullanabilirsiniz:

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

0

Başka bir çözüm, çok hafif, yüksek performanslı ve büyük yük kapasitesi:

Android Eşzamansız Http İstemci kitaplığı: 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!");

            };

        }

    );

}

2
büyük dosya boyutları
yetersiz

1
@Ravi +1 bu kitaplık büyük dosyaları yüklemek için berbat
Anton

Büyük dosyalar göndermek istiyorsanız çok bölümlü için apache mime kitaplıklarını kullanın ve ardından bu kitaplığı kullanarak gönderin.
Ravi

Görüntünün boyutunu sıkıştırmanız ve ardından bu kitaplığı kullanarak görüntüyü yüklemek için aşağıdaki URL'den çözüm buldum: programmerguru.com/android-tutorial/… Umarım bu birilerinin zamanından tasarruf edebilir.
Milan Sheth

@Ravi apache mime size çatışma ve yinelenen sınıf hatası verecektir.
Muhammad Saqib

0

İşte Volley Android Kullanarak Dosya Yüklemek İçin Basit Çözüm ve Tam Örnek

1) Gradle İçe Aktarma

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

2) Şimdi bir Sınıf RequestManager'ı Oluşturun

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) Şimdi, Dosya WebServisini karşıya yükleme talebini işlemek için bir Sınıf Oluşturun

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) Ve Şimdi Servisi Hit için Bunun gibi bir yöntemi çağırın

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

Çözümünüzle şu hatayı alıyorum: java.lang.NoSuchMethodError: Doğrudan yöntem yok <init> (ILjava / lang / String; Lcom / android / volley / Request $ Priority; Lcom / android / volley / Response $ ErrorListener; Lcom / android / voleybol / RetryPolicy;) Lcom / android / voleybol sınıfında V / İstek; veya süper sınıfları ('com.android.volley.Request' bildirimi
/data/data/com.footballscout.app/files/instant-run/dex/slice-slice_4-classes.dex

sınıflarda doğru not ve ithalatı kontrol ettiniz mi?
Hızlı öğrenen

Kullandığım Burada anlatılan bir kez ve cevap github.com/DWorkS/VolleyPlus
SpyZip

1
ve kullandığınız sınıfta ithalatlarınızı kontrol edin, çünkü hata dinleyiciyi işaret ediyormuş gibi voleybol için doğru ithalatı kullanmamanız gerekir, ithalleri tekrar kontrol edin ve ardından projeyi temizleyin, teşekkürler, eğer hala buluyorsanız sorun bana haber ver
Hızlı öğrenen

-1

Bunu yapma şeklim bu. Başkaları için faydalı olabilir:

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

 }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.