(Android)安卓form-data形式上传二进制(binary)文件Volley

本文使用的是Volley网络通讯框架

背景:之前一直是做Web前端开发,现要写一个android程序,web端有现成的上传文件接口,是常用的new FormData()形式,新写的android也要一样使用,可是我用camer2拍照,最终得到的是nv21,束手无策中...

网页multipart/form-data形式上传的二进制文件流,安卓咋整

一、了解form-data的格式要求

Content-Type:multipart/form-data; boundary=yourselfDefinedWord //声明分割符
//下面就是我们的内容
--yourselfDefinedWord
Content-Disposition:form-data; name="字段名称"; filename="userHead.png"
//必须接空行
binary内容
--yourselfDefinedWord //如果还有其他字段内容,用分隔符继续copy上面格式,否则直接用最后的结尾
Content-Disposition:form-data; name="字段名称"
//必须接空行
这是其他字段内容
--yourselfDefinedWord--//结尾格式

如上格式,form-data形式传输的时候,需在Content-Type中定义一个分隔符给后端去分割接收参数,在前端这件事一般浏览器会帮忙做了,android里咱要自己定义一下,然后在拼接参数内容,需要注意的是,大家伙定义bounday都会以“----”开头,因为浏览器是这个规则吧,具体有识之士可以展开说说。每次拼接分隔符前要加上“--”,最后的结尾处要加上“--”

二、实现

public static void uploadFile(String interfaceUrl, final HashMap<String, Object> params) {
    JSONObject parameters = new JSONObject(params);
    RequestQueue requestQueue = Volley.newRequestQueue(mInstance.context);
    String fullUrl="https:apiInterface" + interfaceUrl;
    JsonObjectRequest jsonRequest =new JsonObjectRequest(Request.Method.POST, fullUrl,parameters,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse (JSONObject response){
                    Log.i("successUpload", "onResponse: "+response);
                }
            },new Response.ErrorListener(){
        @Override
        public void onErrorResponse (VolleyError error){
            Log.e("errorUpload", "info: "+error);// 请求失败错误调用
        }
    }
    ){
        private final String fixFormat = "--";
        private final String mFilename = System.currentTimeMillis()+".jpeg";
        private final String splitLine = "\r\n";
        private final String boundary = "joneSplitLineHere"; // 分隔符

        @Override
        public String getBodyContentType() {
            return "multipart/form-data;boundary=" + boundary;
        }
        @Override
        public byte[] getBody() {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(baos);
            // 构建请求体
            try{
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    Bitmap orgBit = (Bitmap) entry.getValue();
                    //压缩并转格式Start
                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                    if(orgBit.compress(Bitmap.CompressFormat.JPEG,100,out)) {
                        out.flush();
                        out.close();
                    }
                    //压缩并转格式End
                    dos.write(getBytes(fixFormat + boundary + splitLine));
                    dos.write(getBytes("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"; filename=\""+ mFilename + "\"" + splitLine));
                    dos.write(getBytes(splitLine));
                    dos.write(out.toByteArray());
                    dos.write(getBytes(splitLine));
                }
                dos.write(getBytes(fixFormat + boundary + fixFormat + splitLine));// 结束标记
            }catch (IOException e){
                e.printStackTrace();
            }

            return baos.toByteArray();
        }
    };
    jsonRequest.setRetryPolicy(new DefaultRetryPolicy(5000, 0, 0));
    jsonRequest.setTag("JoneRequestTag");
    requestQueue.add(jsonRequest);
}
public static byte[] getBytes(String str){
    return str.getBytes();
}

我只用这个传了一个参数,如果要多个参,自己改下“Content-Disposition”那一行,判断不是文件给个name就好了,注意只能有name属性,否则后端不会识别

这个是用了volley框架的,如果要直接套用,注意在build.gradle的dependencies中引入。web前端对build.gradle的理解就是node项目里package.json一些包和配置了

  implementation 'com.mcxiaoke.volley:library:1.0.19'

前面说了是nv21,但这里写的函数接收的参数是bitmap格式的图片文件,附转换方法

public class NV21ToBitmap {
    private RenderScript rs;
    private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic;
    private Type.Builder yuvType, rgbaType;
    private Allocation in, out;

    public NV21ToBitmap(Context context) {
        rs = RenderScript.create(context);
        yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
    }

    public Bitmap nv21ToBitmap(byte[] nv21, int width, int height){
        if (yuvType == null){
            yuvType = new Type.Builder(rs, Element.U8(rs)).setX(nv21.length);
            in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);

            rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height);
            out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
        }

        in.copyFrom(nv21);

        yuvToRgbIntrinsic.setInput(in);
        yuvToRgbIntrinsic.forEach(out);

        Bitmap bmpout = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        out.copyTo(bmpout);

        return bmpout;

    }

}
Bitmap val= new NV21ToBitmap(this).nv21ToBitmap(nv21, mPreviewSize.getWidth(), mPreviewSize.getHeight()); //调用转换

HashMap map=new HashMap();
map.put("file", val);
HttpHelper.getInstance(this).uploadImage("FacePicCompare",map); //调用上传

写的不好之处,👏🏻指出

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值