Volley를 사용하여 Android에서 "multipart / form-data"POST를 보내는 방법


89

multipart/form-data아직 Volley를 사용하여 Android 에서 POST를 보낼 수있는 사람이 있습니까? 나는 image/pngPOST 요청을 사용하여 서버 에 업로드하는 데 성공하지 못했고 누군가가 있는지 궁금합니다.

이 작업을 수행하는 기본 방법 public byte[] getPostBody()Request.java클래스 에서 재정의 File하고 경계에 대한 빈 헤더 키로 거기에 첨부하는 것입니다. 그러나 내 파일을 Stringfor 로 변환 Map<String, String> postParams한 다음 다시 인코딩하는 것은 둔감하고 우아하지 않습니다. 또한 나는 내 시도에 실패했습니다. 이것이 우리가이 라이브러리로 전환하는 것을 방해하는 유일한 이유입니다.

어쨌든 모든 생각과 답변은 대단히 감사합니다. 도와 주셔서 감사합니다.

답변:


75

나는 이것에 대해 틀릴 수도 있지만 com.android.volley.toolbox.HttpStack기본 HurlStack버전 ( 버전> Gingerbread 또는 HttpClientStack)이 처리하지 않기 때문에 이것을 위해 직접 구현해야한다고 생각합니다 multipart/form-data.

편집하다:

그리고 실제로 나는 틀렸다. 다음 MultipartEntity과 같이 요청에서 사용할 수 있습니다 .

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

꽤 원시적이지만 이미지와 간단한 문자열로 시도해 보았고 작동합니다. 응답은 자리 표시 자이며이 경우 응답 문자열을 반환하는 것은 의미가 없습니다. MultipartEntity를 사용하기 위해 apache httpmime을 사용하는 데 문제가 있었기 때문에 https://code.google.com/p/httpclientandroidlib/ 를 사용했지만 더 나은 방법이 있는지 모르겠습니다. 도움이되기를 바랍니다.

편집하다

httpclientandroidlib를 사용하지 않고 httpmime를 사용할 수 있으며 유일한 종속성은 httpcore입니다.


2
@LOG_TAG : 큰 파일을 지원하지 않습니다. 진행률 표시 줄도 지원하지 않습니다. 그 이유는 모든 데이터를 단일 바이트 []에 저장하기 때문입니다. 큰 파일의 경우 발리에서는 불가능 해 보이는 InputStream을 사용하려고합니다. 그러나 그들은 (발리 개발자) 발리가 큰 파일을 위해 만들어지지 않았다고 말합니다.
Patrick Boos 2014 년

9
@alex MultipartRequest를 사용하는 방법에 대한 코드를 넣을 수 있습니까?
Krishna Shrestha 2014

4
org.apache.http.entity.ContentType : java.lang.NoClassDefFoundError가 :이 오류 얻을
밀라 드

1
Apache http를 사용하는 MultipartEntity. 아파치 멀티 파트 라이브러리없이하고 싶습니다. 어떻게 할 수 있습니까?
JosephM 2015

1
return entity.getContentType (). getValue (); 오류
Volodymyr Kulyk

14

I / O (약 4:05)의 프레젠테이션에서 언급했듯이 Volley는 대용량 페이로드에 대해 "끔찍합니다". 내가 이해했듯이 이는 (큰) 파일을 수신 / 전송하는 데 Volley를 사용하지 않는 것을 의미합니다. 코드를 보면 멀티 파트 양식 데이터를 처리하도록 설계되지 않은 것 같습니다 (예 : Request.java에는 하드 코딩 된 "application / x-www-form-urlencoded"와 함께 getBodyContentType ()이 있습니다. HttpClientStack :: createHttpRequest ()는 바이트 만 처리 할 수 ​​있음) [] 등 ...). 아마 당신은 멀티 파트를 처리 할 수있는 구현을 만들 수있을 것입니다.하지만 내가 당신이라면 그냥 다음과 같이 MultipartEntity와 함께 HttpClient를 직접 사용할 것입니다.

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

새로운 HttpClient (즉, 내장 된 것이 아님) 가 필요할 수도 있고 더 나은 방법은 최신 HttpClient와 함께 Volley를 사용하는 것입니다.


1
도움을 주셔서 감사합니다. 귀하의 블로그는 내가 가지고 있지 않은 것을 보여줍니다. Alex의 솔루션이 작동하지 않으면 위의 링크를 통해 제안을 시도하겠습니다. 건배!
AllDayAmazing 2013 년

안녕하세요 @Ogre_BGR, 스냅 코드를 사용하여 이미지를 업로드하는 방법에 대한 전체 샘플을 제공해 주시겠습니까? 나는 많은 샘플만을 시도했지만 매우 오래되어 작동하지 않습니다. 주셔서 감사합니다
티아고

이제 Multipart가 지원됩니다. 이 페이지의 다른 답변을보십시오.
Martin Konecny ​​2015-08-26

1
다른 사용자가 직접 갈 수 있도록 @MartinKonecny 의견에 정답을 연결하십시오
Ognyan

단일 요청에서 멀티 파트 형식과 함께 다른 매개 변수를 어떻게 추가 할 수 있습니까?
casillas

10

2015/08/26 업데이트 :

더 이상 사용되지 않는 HttpEntity를 사용하지 않으려면 다음은 내 작업 샘플 코드입니다 (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);
    }
}

업데이트 끝

이것은 내 작업 샘플 코드입니다 (작은 크기 파일로만 테스트 됨).

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
일부 서버는 매우 까다 롭습니다. 문제가있는 경우 ";"사이에 공백을 추가하십시오. Content-Disposition을 빌드 할 때 "filename ="및 "multipart / form-data; boundary ="+ boundary;
Kevin

@Kevin의 의견에 감사드립니다. 사실 확인해야 할 서버 앱이 많지 않았습니다. :-)
BNK

@HemsLodha : pls는 내 다음 질문 stackoverflow.com/questions/32240177/ 에서 RacZo의 답변을 살펴보고 도움이 될 수 있는지 여부를 확인합니다. :)
BNK

1
나는 volley로 post multipart 요청을 보내고 마침내 매개 변수를 url로 설정하면 작동합니다. @BNK를 도와 주셔서 감사합니다.
JosephM

@ user3561494는 비디오와 같은 큰 크기의 파일을 권장하지 오기 '
BNK

9

업로드 진행률과 함께 멀티 파트 요청 완료

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

    }
}

샘플 사용

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_-귀하의 코드를 시도했습니다 :하지만이 오류가 발생합니다 : MultipartRequest.getBody : ByteArrayOutputStream에 쓰는 IOException. 당신은 제발 도와 드릴까요
티아고

나는 당신의 코드가 없으며 다른 질문을 여는 데 더 좋은 것을 제안 할 수 없습니다. 가장 가능한 이유는 가상 메모리가 부족했기 때문일 수 있습니다.
AZ_

1
나는 새로운 질문을 열었습니다 : stackoverflow.com/questions/31474585/… 당신은 pls를 도울 수 있습니까? 감사합니다
Thiago

단일 요청에서 멀티 파트 형식과 함께 다른 매개 변수를 어떻게 추가 할 수 있습니까?
casillas

@casillas는 요청 헤더에 키 값 쌍을 추가합니다.
AZ_

8

멀티 파트 요청에서 POST 매개 변수를 전송하려는 개발자를위한 매우 간단한 접근 방식입니다.

Request.java를 확장하는 클래스에서 다음과 같이 변경하십시오.

먼저 다음 상수를 정의하십시오.

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;

도우미 기능을 추가하여 게시물 본문을 만듭니다.

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 () 및 getBodyContentType 재정의

public String getBodyContentType() {
    return MULTIPART_FORMDATA;
}

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

1
매우 간단하고 완벽하게 작동합니다! sbPost.append("--" + BOUNDARY + "--");사용중인 API에 닫는 태그가 필요하기 때문에 반환 직전에 해야 했습니다
Sirens

1
당신이 너무 :) 감사
Arpit 라탄에게

감사! 이것은 프론트 엔드에서 나를 위해 일했지만 백엔드 특히 nodejs가 그것을 파싱하는 데 문제가 있습니까? 그런 경험이 있습니까?
Woppi

1
백엔드 경험이 없어서 죄송합니다 :(
Arpit Ratan dec

@Arpit 덕분에, 내가 대신이 헬퍼 클래스를 사용하여 내 문제를 해결할 수 있었다 gist.github.com/anggadarkprince/...
Woppi

4

SO에 대한 첫 번째 대답.

나는 같은 문제가 발생했고 @alex의 코드가 매우 유용하다는 것을 알았습니다. HashMap을 통해 필요한만큼 많은 매개 변수를 전달하기 위해 몇 가지 간단한 수정을 수행했으며 기본적으로 parseNetworkResponse()StringRequest에서 복사 했습니다. 나는 온라인에서 검색을했고, 그러한 일반적인 작업이 거의 답이 없다는 것을 알고 너무 놀랐습니다. 어쨌든 코드가 도움이 되길 바랍니다.

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

그리고 다음과 같이 클래스를 사용할 수 있습니다.

    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

페이로드가 큰 고성능으로 매우 가볍고 또 다른 솔루션 :

Android 비동기 Http 클라이언트 라이브러리 : 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
큰 파일 크기는 메모리 예외 알려주지
라비에게

1
@Ravi +1이 라이브러리는 대용량 파일을 업로드하는 데 짜증이납니다
Anton

대용량 파일을 보내려면 multipart에 apache mime 라이브러리를 사용하고이 라이브러리를 사용하여 게시하십시오.
Ravi

아래 URL에서 해결책을 찾은 이미지를 업로드하려면 이미지 크기를 압축 한 다음이 라이브러리를 사용해야합니다. programmerguru.com/android-tutorial/… 이것이 누군가의 시간을 절약 할 수 있기를 바랍니다.
Milan Sheth

@Ravi apache mime은 충돌 및 중복 클래스 오류를 제공합니다.
Muhammad Saqib

0

다음은 Volley Android를 사용하여 파일을 업로드하는 간단한 솔루션과 완전한 예입니다.

1) Gradle 가져 오기

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

2) 이제 클래스 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) 이제 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) 이제 다음과 같은 메서드를 호출하여 서비스를 실행하십시오.

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

솔루션에서이 오류가 발생합니다. java.lang.NoSuchMethodError : No direct method <init> (ILjava / lang / String; Lcom / android / volley / Request $ Priority; Lcom / android / volley / Response $ ErrorListener; Lcom / android / volley / RetryPolicy;) Lcom / android / volley / Request 클래스의 V; 또는 해당 수퍼 클래스 ( 'com.android.volley.Request'선언이 /data/data/com.footballscout.app/files/instant-run/dex/slice-slice_4-classes.dex에 표시됨)
SpyZip

클래스에서 올바른 gradle과 가져 오기를 확인 했습니까?
빠른 학습자

내가 사용하는 여기에 설명 한 번 당신의 대답 github.com/DWorkS/VolleyPlus
SpyZip

1
오류가 오류 리스너를 가리키는 것처럼 발리에 대한 올바른 가져 오기를 사용해서는 안되기 때문에 사용하는 클래스에서 가져 오기를 확인하고 가져 오기를 다시 확인하고 gradle 다음 프로젝트를 정리하십시오. 문제는 알려 않습니다
빠른 학습자

-1

이것이 제 방식입니다. 다른 사람들에게 유용 할 수 있습니다.

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

 }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.