使用 Volley 和不使用 HttpEntity 处理 POST 多部分请求 [英] Working POST Multipart Request with Volley and without HttpEntity

查看:29
本文介绍了使用 Volley 和不使用 HttpEntity 处理 POST 多部分请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这不是一个真正的问题,但是,我想在这里分享我的一些工作代码,供您在需要时参考.

正如我们所知,HttpEntity 已从 API22 中弃用,并自 API23 起完全删除.目前,我们无法在 Android 上访问 HttpEntity Reference不再是开发人员 (404).因此,以下是我的 POST Multipart Request with Volley and without HttpEntity 的工作示例代码.它正在运行,并使用 Asp.Net Web API 进行了测试.当然,代码可能只是一个基本示例,发布了两个现有的可绘制文件,也不是所有情况下的最佳解决方案,也不是很好的调优.

MultipartActivity.java:

package com.example.multipartvolley;导入 android.app.Activity;导入 android.content.Context;导入 android.graphics.Bitmap;导入 android.graphics.drawable.BitmapDrawable;导入 android.graphics.drawable.Drawable;导入 android.os.Bundle;导入 android.support.v4.content.ContextCompat;导入 android.view.Menu;导入 android.view.MenuItem;导入 android.widget.Toast;导入 com.android.volley.NetworkResponse;导入 com.android.volley.Response;导入 com.android.volley.VolleyError;导入 java.io.ByteArrayInputStream;导入 java.io.ByteArrayOutputStream;导入 java.io.DataOutputStream;导入 java.io.IOException;公共类 MultipartActivity 扩展 Activity {私有最终上下文上下文 = this;private final String twoHyphens = "--";private final String lineEnd = "
";私有最终字符串边界 = "apiclient-" + System.currentTimeMillis();private final String mimeType = "multipart/form-data;boundary="+boundary;私有字节[] multipartBody;@覆盖protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_multipart);byte[] fileData1 = getFileDataFromDrawable(context, R.drawable.ic_action_android);byte[] fileData2 = getFileDataFromDrawable(context, R.drawable.ic_action_book);ByteArrayOutputStream bos = new ByteArrayOutputStream();DataOutputStream dos = new DataOutputStream(bos);尝试 {//第一个文件buildPart(dos, fileData1, "ic_action_android.png");//第二个文件buildPart(dos, fileData2, "ic_action_book.png");//在文件数据之后发送必要的多部分表单数据dos.writeBytes(twoHyphens + bounds + twoHyphens + lineEnd);//传递给多部分主体multipartBody = bos.toByteArray();} catch (IOException e) {e.printStackTrace();}String url = "http://192.168.1.100/api/postfile";MultipartRequest multipartRequest = new MultipartRequest(url, null, mimeType, multipartBody, new Response.Listener() {@覆盖公共无效onResponse(网络响应响应){Toast.makeText(context, "上传成功!", Toast.LENGTH_SHORT).show();}}, 新的 Response.ErrorListener() {@覆盖公共无效onErrorResponse(VolleyError错误){Toast.makeText(context, "上传失败!
" + error.toString(), Toast.LENGTH_SHORT).show();}});VolleySingleton.getInstance(context).addToRequestQueue(multipartRequest);}@覆盖公共布尔 onCreateOptionsMenu(菜单菜单){//给菜单充气;如果它存在,这会将项目添加到操作栏.getMenuInflater().inflate(R.menu.menu_multipart, menu);返回真;}@覆盖公共布尔 onOptionsItemSelected(MenuItem item) {//在此处处理操作栏项目的点击.操作栏将//自动处理 Home/Up 按钮上的点击,这么长时间//当您在 AndroidManifest.xml 中指定父活动时.int id = item.getItemId();//不检查SimplifiableIfStatement如果(id == R.id.action_settings){返回真;}返回 super.onOptionsItemSelected(item);}private void buildPart(DataOutputStream dataOutputStream, byte[] fileData, String fileName) 抛出 IOException {dataOutputStream.writeBytes(twoHyphens + bounds + lineEnd);dataOutputStream.writeBytes("Content-Disposition: form-data; name="uploaded_file"; filename=""+ 文件名 + """ + lineEnd);dataOutputStream.writeBytes(lineEnd);ByteArrayInputStream fileInputStream = new ByteArrayInputStream(fileData);int bytesAvailable = fileInputStream.available();int maxBufferSize = 1024 * 1024;int bufferSize = Math.min(bytesAvailable, maxBufferSize);字节 [] 缓冲区 = 新字节 [缓冲区大小];//读取文件并将其写入表单...int bytesRead = fileInputStream.read(buffer, 0, bufferSize);而(字节读取> 0){dataOutputStream.write(buffer, 0, bufferSize);bytesAvailable = fileInputStream.available();bufferSize = Math.min(bytesAvailable, maxBufferSize);bytesRead = fileInputStream.read(buffer, 0, bufferSize);}dataOutputStream.writeBytes(lineEnd);}私有字节[] getFileDataFromDrawable(上下文上下文,int id){Drawable drawable = ContextCompat.getDrawable(context, id);位图 bitmap = ((BitmapDrawable) drawable).getBitmap();ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream);返回 byteArrayOutputStream.toByteArray();}}

MultipartRequest.java:

package com.example.multipartvolley;导入 com.android.volley.AuthFailureError;导入 com.android.volley.NetworkResponse;导入 com.android.volley.ParseError;导入 com.android.volley.Request;导入 com.android.volley.Response;导入 com.android.volley.VolleyError;导入 com.android.volley.toolbox.HttpHeaderParser;导入 java.util.Map;类 MultipartRequest 扩展了 Request{私有最终 Response.Listener监听器;私人最终 Response.ErrorListener mErrorListener;private final MapmHeaders;私有最终字符串mMimeType;私有最终字节[] mMultipartBody;public MultipartRequest(String url, Map headers, String mimeType, byte[] multipartBody, Response.Listener listener, Response.ErrorListener errorListener) {super(Method.POST, url, errorListener);this.mListener = 监听器;this.mErrorListener = errorListener;this.mHeaders = 标题;this.mMimeType = mimeType;this.mMultipartBody = multipartBody;}@覆盖公共地图<字符串,字符串>getHeaders() 抛出 AuthFailureError {返回 (mHeaders != null) ?mHeaders : super.getHeaders();}@覆盖公共字符串 getBodyContentType() {返回 mMimeType;}@覆盖public byte[] getBody() 抛出 AuthFailureError {返回 mMultipartBody;}@覆盖受保护的响应<NetworkResponse>解析网络响应(网络响应响应){尝试 {返回 Response.success(回复,HttpHeaderParser.parseCacheHeaders(response));} 捕获(异常 e){返回 Response.error(new ParseError(e));}}@覆盖受保护的无效交付响应(网络响应响应){mListener.onResponse(响应);}@覆盖公共无效交付错误(VolleyError 错误){mErrorListener.onErrorResponse(error);}}

更新:

正文部分,请参考下方@Oscar的回答.

解决方案

我重写了你的代码@RacZo 和@BNK,更加模块化和易于使用

VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, url, new Response.Listener() {@覆盖公共无效onResponse(网络响应响应){String resultResponse = new String(response.data);//解析成功输出}}, 新的 Response.ErrorListener() {@覆盖公共无效onErrorResponse(VolleyError错误){error.printStackTrace();}}) {@覆盖protected Map获取参数(){映射<字符串,字符串>params = new HashMap<>();params.put("api_token", "gh659gjhvdyudo973823tt9gvjf7i6ric75r76");params.put("name", "Angga");params.put("location", "印度尼西亚");params.put("about", "UI/UX Designer");params.put("联系方式", "angga@email.com");返回参数;}@覆盖protected Map获取字节数据(){映射<字符串,数据部分>params = new HashMap<>();//文件名可以找到文件库或从真实路径直接访问//现在只从 ImageView 获取位图数据params.put("avatar", new DataPart("file_avatar.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mAvatarImage.getDrawable()), "image/jpeg"));params.put("cover", new DataPart("file_cover.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mCoverImage.getDrawable()), "image/jpeg"));返回参数;}};VolleySingleton.getInstance(getBaseContext()).addToRequestQueue(multipartRequest);

在我的gist上查看完整的代码VolleyMultipartRequest.>

This is not really a question, however, I would like to share some of my working code here for your reference when you need.

As we know that HttpEntity is deprecated from API22 and comletely removed since API23. At the moment, we cannot access HttpEntity Reference on Android Developer anymore (404). So, the following is my working sample code for POST Multipart Request with Volley and without HttpEntity. It's working, tested with Asp.Net Web API. Of course, the code perhaps is just a basic sample that posts two existed drawable files, also is not the best solution for all cases, and not good tuning.

MultipartActivity.java:

package com.example.multipartvolley;

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 android.widget.Toast;

import com.android.volley.NetworkResponse;
import com.android.volley.Response;
import com.android.volley.VolleyError;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;


public class MultipartActivity extends Activity {

    private final Context context = this;
    private final String twoHyphens = "--";
    private final String lineEnd = "
";
    private final String boundary = "apiclient-" + System.currentTimeMillis();
    private final String mimeType = "multipart/form-data;boundary=" + boundary;
    private byte[] multipartBody;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_multipart);

        byte[] fileData1 = getFileDataFromDrawable(context, R.drawable.ic_action_android);
        byte[] fileData2 = getFileDataFromDrawable(context, R.drawable.ic_action_book);

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(bos);
        try {
            // the first file
            buildPart(dos, fileData1, "ic_action_android.png");
            // the second file
            buildPart(dos, fileData2, "ic_action_book.png");
            // send multipart form data necesssary after file data
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
            // pass to multipart body
            multipartBody = bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }

        String url = "http://192.168.1.100/api/postfile";
        MultipartRequest multipartRequest = new MultipartRequest(url, null, mimeType, multipartBody, new Response.Listener<NetworkResponse>() {
            @Override
            public void onResponse(NetworkResponse response) {
                Toast.makeText(context, "Upload successfully!", Toast.LENGTH_SHORT).show();
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Toast.makeText(context, "Upload failed!
" + error.toString(), Toast.LENGTH_SHORT).show();
            }
        });

        VolleySingleton.getInstance(context).addToRequestQueue(multipartRequest);
    }

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

    private void buildPart(DataOutputStream dataOutputStream, byte[] fileData, String fileName) throws IOException {
        dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
        dataOutputStream.writeBytes("Content-Disposition: form-data; name="uploaded_file"; filename=""
                + fileName + """ + lineEnd);
        dataOutputStream.writeBytes(lineEnd);

        ByteArrayInputStream fileInputStream = new ByteArrayInputStream(fileData);
        int bytesAvailable = fileInputStream.available();

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

        // read file and write it into form...
        int bytesRead = fileInputStream.read(buffer, 0, bufferSize);

        while (bytesRead > 0) {
            dataOutputStream.write(buffer, 0, bufferSize);
            bytesAvailable = fileInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);
        }

        dataOutputStream.writeBytes(lineEnd);
    }

    private byte[] getFileDataFromDrawable(Context context, int id) {
        Drawable drawable = ContextCompat.getDrawable(context, id);
        Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream);
        return byteArrayOutputStream.toByteArray();
    }
}

MultipartRequest.java:

package com.example.multipartvolley;

import com.android.volley.AuthFailureError;
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 java.util.Map;

class MultipartRequest extends Request<NetworkResponse> {
    private final Response.Listener<NetworkResponse> mListener;
    private final Response.ErrorListener mErrorListener;
    private final Map<String, String> mHeaders;
    private final String mMimeType;
    private final byte[] mMultipartBody;

    public MultipartRequest(String url, Map<String, String> headers, String mimeType, byte[] multipartBody, Response.Listener<NetworkResponse> listener, Response.ErrorListener errorListener) {
        super(Method.POST, url, errorListener);
        this.mListener = listener;
        this.mErrorListener = errorListener;
        this.mHeaders = headers;
        this.mMimeType = mimeType;
        this.mMultipartBody = multipartBody;
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        return (mHeaders != null) ? mHeaders : super.getHeaders();
    }

    @Override
    public String getBodyContentType() {
        return mMimeType;
    }

    @Override
    public byte[] getBody() throws AuthFailureError {
        return mMultipartBody;
    }

    @Override
    protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) {
        try {
            return Response.success(
                    response,
                    HttpHeaderParser.parseCacheHeaders(response));
        } catch (Exception e) {
            return Response.error(new ParseError(e));
        }
    }

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

    @Override
    public void deliverError(VolleyError error) {
        mErrorListener.onErrorResponse(error);
    }
}

UPDATE:

For text part, please refer to @Oscar's answer below.

解决方案

I rewrite your code @RacZo and @BNK more modular and easy to use like

VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, url, new Response.Listener<NetworkResponse>() {
    @Override
    public void onResponse(NetworkResponse response) {
        String resultResponse = new String(response.data);
        // parse success output
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {                
        error.printStackTrace();
    }
}) {
    @Override
    protected Map<String, String> getParams() {
        Map<String, String> params = new HashMap<>();
        params.put("api_token", "gh659gjhvdyudo973823tt9gvjf7i6ric75r76");
        params.put("name", "Angga");
        params.put("location", "Indonesia");
        params.put("about", "UI/UX Designer");
        params.put("contact", "angga@email.com");
        return params;
    }

    @Override
    protected Map<String, DataPart> getByteData() {
        Map<String, DataPart> params = new HashMap<>();
        // file name could found file base or direct access from real path
        // for now just get bitmap data from ImageView
        params.put("avatar", new DataPart("file_avatar.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mAvatarImage.getDrawable()), "image/jpeg"));
        params.put("cover", new DataPart("file_cover.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mCoverImage.getDrawable()), "image/jpeg"));

        return params;
    }
};

VolleySingleton.getInstance(getBaseContext()).addToRequestQueue(multipartRequest);

Check full of code VolleyMultipartRequest at my gist.

这篇关于使用 Volley 和不使用 HttpEntity 处理 POST 多部分请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆