本文使用的是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); //调用上传
写的不好之处,👏🏻指出