Cách gửi BÀI ĐĂNG “nhiều phần / dữ liệu biểu mẫu” trong Android với Volley


89

Có ai có thể hoàn thành việc gửi multipart/form-dataBÀI ĐĂNG trong Android với Volley chưa? Tôi đã không thành công khi cố gắng tải lên một image/pngyêu cầu POST bằng cách sử dụng máy chủ của chúng tôi và tôi tò mò xem có ai có không.

Tôi tin rằng cách mặc định để làm điều này là ghi đè public byte[] getPostBody()trong Request.javalớp và đính kèm vào Fileđó với một khóa Tiêu đề trống cho ranh giới. Tuy nhiên, việc chuyển đổi tệp của tôi thành a Stringcho Map<String, String> postParamsvà sau đó mã hóa lại nó có vẻ khó hiểu và không thực sự thanh lịch. Ngoài ra, tôi đã không thành công trong những nỗ lực của mình. Đây thực sự là điều duy nhất ngăn cản chúng tôi chuyển sang thư viện này.

Dù sao, mọi suy nghĩ và câu trả lời đều được đánh giá cực kỳ cao. Cảm ơn sự giúp đỡ của bạn.

Câu trả lời:


75

Tôi có thể sai về điều này nhưng tôi nghĩ bạn cần phải triển khai của riêng bạn com.android.volley.toolbox.HttpStackcho điều này vì những cái mặc định ( HurlStacknếu phiên bản> Gingerbread hoặc HttpClientStack) không xử lý được multipart/form-data.

Biên tập:

Và quả thực là tôi đã nhầm. Tôi đã có thể làm điều đó bằng cách sử dụng MultipartEntitytrong Yêu cầu như thế này:

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

Nó khá thô nhưng tôi đã thử nó với một hình ảnh và một chuỗi đơn giản và nó hoạt động. Phản hồi là một trình giữ chỗ, không có ý nghĩa gì khi trả về Chuỗi phản hồi trong trường hợp này. Tôi gặp sự cố khi sử dụng apache httpmime để sử dụng MultipartEntity vì vậy tôi đã sử dụng https://code.google.com/p/httpclientandroidlib/ này không biết có cách nào tốt hơn không. Hy vọng nó giúp.

Biên tập

Bạn có thể sử dụng httpmime mà không cần sử dụng httpclientandroidlib, phụ thuộc duy nhất là httpcore.


2
@LOG_TAG: Điều này sẽ không hỗ trợ các tệp lớn. Nó cũng không hỗ trợ thanh tiến trình. Lý do là nó sẽ đặt tất cả dữ liệu trong một byte duy nhất []. Đối với các tệp lớn, bạn muốn sử dụng InputStream, điều này dường như không khả thi với volley. Nhưng họ (nhà phát triển bóng chuyền) cũng nói rằng bóng chuyền không được tạo ra cho các tệp lớn.
Patrick Boos

9
@alex bạn có thể đặt một số mã cách sử dụng MultipartRequest không?
Krishna Shrestha

5
Tôi gặp lỗi này: java.lang.NoClassDefFoundError: org.apache.http.entity.ContentType
Milad

1
MultipartEntity sử dụng apache http. tôi muốn làm điều đó mà không có thư viện đa phần apache. tôi có thể làm cái này như thế nào.
JosephM

1
trả về entity.getContentType (). getValue (); Lỗi
Volodymyr Kulyk

14

Như đã đề cập trong bài thuyết trình tại I / O (khoảng 4:05), Volley “khủng khiếp” đối với trọng tải lớn. Theo tôi hiểu, điều đó có nghĩa là không sử dụng Volley để nhận / gửi các tệp (lớn). Nhìn vào mã, có vẻ như nó thậm chí không được thiết kế để xử lý dữ liệu biểu mẫu nhiều phần (ví dụ: Request.java có getBodyContentType () với mã cứng "application / x-www-form-urlencoded"; HttpClientStack :: createHttpRequest () chỉ có thể xử lý byte [], Vân vân...). Có lẽ bạn sẽ có thể tạo triển khai có thể xử lý nhiều phần nhưng Nếu tôi là bạn, tôi sẽ chỉ sử dụng HttpClient trực tiếp với MultipartEntity như:

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

Bạn có thể cần HttpClient mới hơn (tức là không phải tích hợp sẵn) hoặc thậm chí tốt hơn, hãy sử dụng Volley với HttpClient mới hơn


1
Cảm ơn rất nhiều vì sự giúp đỡ, blog của bạn cho tôi thấy điều gì đó mà tôi sẽ không có. Tôi sẽ thử đề xuất của bạn qua liên kết ở trên nếu tôi không thể làm cho giải pháp của Alex hoạt động. Chúc mừng!
AllDayAmazing

Xin chào @Ogre_BGR, Bạn có thể vui lòng cung cấp mẫu đầy đủ về cách tải hình ảnh lên bằng mã snap của mình không. Tôi đã thử nhiều mẫu chỉ, nhưng chúng rất cũ và tôi không thể làm cho nó hoạt động. Cảm ơn bạn
Thiago

Multipart hiện đã được hỗ trợ. Xem các câu trả lời khác trên trang này.
Martin Konecny

1
@MartinKonecny xin vui lòng liên kết các câu trả lời đúng trong nhận xét của bạn để người dùng khác có thể đi trực tiếp vào nó
Ognyan

Làm cách nào để tôi có thể thêm các tham số khác cùng với định dạng nhiều phần trong một yêu cầu?
casillas

10

CẬP NHẬT 2015/08/26:

Nếu bạn không muốn sử dụng HttpEntity không dùng nữa, đây là mã mẫu hoạt động của tôi (được thử nghiệm với 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);
    }
}

CẬP NHẬT KẾT THÚC

Đây là mã mẫu làm việc của tôi (chỉ được thử nghiệm với các tệp kích thước nhỏ):

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
Một số máy chủ RẤT kén chọn. Nếu bạn gặp sự cố, hãy thêm dấu cách giữa ";" và "filename =" khi xây dựng Nội dung-Bố trí và "đa phần / biểu mẫu-dữ liệu; ranh giới =" + ranh giới;
Kevin

Cảm ơn bình luận của bạn @Kevin. Trên thực tế, tôi không có nhiều ứng dụng máy chủ để kiểm tra điều đó :-)
BNK

@HemsLodha: làm ơn hãy xem câu trả lời của RacZo tại câu hỏi sau đây của tôi stackoverflow.com/questions/32240177/… để xem liệu nó có thể giúp bạn hay không :)
BNK

1
Tôi đang gửi yêu cầu nhiều phần đăng với volley và cuối cùng đặt tham số thành url và nó hoạt động. Cảm ơn sự giúp đỡ @BNK.
JosephM

@ user3561494 không khuyến khích các tệp có kích thước lớn như video
BNK

9

Hoàn thành Yêu cầu Multipart với Tiến độ Tải lê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);
            }
        }

    }
}

Sử dụng mẫu

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

    }

Xin chào @AZ_ - tôi đã thử mã của bạn: Nhưng tôi gặp lỗi này: MultipartRequest.getBody: IOException ghi vào ByteArrayOutputStream. Bạn có thể giúp xin vui lòng
Thiago

Tôi không có mã của bạn, tôi không thể đề xuất bất cứ điều gì tốt hơn để mở một câu hỏi khác, lý do có thể xảy ra nhất có thể là bạn hết bộ nhớ ảo.
AZ_

1
Tôi có Mở Tôi mới Câu hỏi: stackoverflow.com/questions/31474585/… Bạn có thể giúp được không. cảm ơn bạn
Thiago

Làm cách nào để tôi có thể thêm các tham số khác cùng với định dạng nhiều phần trong một yêu cầu?
casillas

@casillas thêm cặp giá trị khóa vào tiêu đề của yêu cầu.
AZ_

8

Một cách tiếp cận rất đơn giản cho những nhà phát triển chỉ muốn gửi các tham số POST trong yêu cầu nhiều phần.

Thực hiện các thay đổi sau trong lớp mở rộng Request.java

Đầu tiên hãy xác định các hằng số này:

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;

Thêm chức năng trợ giúp để tạo nội dung bài đăng cho bạn:

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

Ghi đè getBody () và getBodyContentType

public String getBodyContentType() {
    return MULTIPART_FORMDATA;
}

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

1
Rất đơn giản và hoạt động hoàn hảo! Tôi phải làm sbPost.append("--" + BOUNDARY + "--");ngay trước khi quay lại vì API tôi đang sử dụng yêu cầu thẻ đóng
Sirens

1
Cảm ơn bạn rất nhiều :)
Arpit Ratan

Cảm ơn! Điều này đã làm việc cho tôi trên front-end nhưng back-end cụ thể là nodejs đang gặp sự cố khi phân tích cú pháp? Bạn đã từng trải qua điều đó chưa?
Woppi 21/12/16

1
Xin lỗi tôi không có kinh nghiệm phụ trợ :(
Arpit Ratan

@Arpit cảm ơn, tôi đã có thể giải quyết vấn đề của mình bằng cách sử dụng lớp trợ giúp này thay vì gist.github.com/anggadarkprince/…
Woppi

4

Câu trả lời đầu tiên trên SO.

Tôi đã gặp phải vấn đề tương tự và thấy mã của @alex rất hữu ích. Tôi đã thực hiện một số sửa đổi đơn giản để truyền nhiều tham số nếu cần thông qua HashMap và về cơ bản đã sao chép parseNetworkResponse()từ StringRequest. Tôi đã tìm kiếm trực tuyến và rất ngạc nhiên khi phát hiện ra rằng một nhiệm vụ phổ biến như vậy hiếm khi được trả lời. Dù sao, tôi ước mã có thể giúp:

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

Và bạn có thể sử dụng lớp như sau:

    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

Một giải pháp khác, rất nhẹ với hiệu suất cao với tải trọng lớn:

Thư viện ứng dụng khách Http không đồng bộ của 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!");

            };

        }

    );

}

2
kích thước file lớn đưa ra bộ nhớ ngoại lệ
Ravi

1
@Ravi 1 thư viện này hút để tải lên tập tin lớn
Anton

nếu bạn muốn gửi các tệp lớn, hãy sử dụng thư viện mime apache cho nhiều phần và sau đó đăng nó bằng thư viện này.
Ravi

Bạn cần nén kích thước của hình ảnh và sau đó sử dụng thư viện này để tải lên hình ảnh mà tôi đã tìm thấy giải pháp từ URL bên dưới: programmmerguru.com/android-tutorial/… Tôi hy vọng điều này có thể tiết kiệm thời gian của ai đó.
Milan Sheth

@Ravi apache mime sẽ cung cấp cho bạn lỗi xung đột và trùng lặp lớp.
Muhammad Saqib

0

Đây là giải pháp đơn giản và ví dụ đầy đủ để tải lên tệp bằng Volley Android

1) Nhập Gradle

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

2) Bây giờ tạo một Class RequestManager

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) Bây giờ Tạo một lớp để xử lý Yêu cầu tải lên Tệp 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) Và ngay bây giờ hãy gọi phương pháp như thế này để truy cập dịch vụ

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

Tôi gặp lỗi này với giải pháp của bạn: java.lang.NoSuchMethodError: Không có phương thức trực tiếp <init> (ILjava / lang / String; Lcom / android / volley / Request $ Priority; Lcom / android / volley / Response $ ErrorListener; Lcom / android / volley / RetryPolicy;) V trong lớp Lcom / android / volley / Yêu cầu; hoặc các siêu lớp của nó (khai báo 'com.android.volley.Request' xuất hiện trong /data/data/com.footballscout.app/files/instant-run/dex/slice-slice_4-classes.dex)
SpyZip

bạn đã kiểm tra xem có đúng lớp và nhập trong các lớp không?
học nhanh

Tôi đã từng một lần được mô tả ở đây và câu trả lời của bạn github.com/DWorkS/VolleyPlus
SpyZip

1
và kiểm tra các lần nhập của bạn trong lớp mà bạn đang sử dụng vì bạn không được sử dụng các phép nhập đúng cho volley như lỗi đang trỏ trên trình nghe lỗi, hãy kiểm tra lại các lần nhập và phân loại sau đó làm sạch dự án, cảm ơn, nếu bạn vẫn tìm thấy lỗi vấn đề làm cho tôi biết
học nhanh

-1

Đây là cách làm của tôi. Nó có thể hữu ích cho những người khác:

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

 }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.