最近遇到这样一个需求:要做一个仿微信朋友圈的功能,要求上传最多九张图到七牛。七牛有上传图片的接口,但是每次只能上传一张。如果是九张图片一齐上传,使用for循环的话肯定不行的,很容易出错。因为上传七牛的动作是在子线程完成的,for循环是在主线程的,这就相当于同时开启十个子线程来上传图片,而且都是耗时线程,很容易会ANR的。
最好的解决办法应该是先压缩图片,在200k-300k之间,保证图片不失真,然后一张一张上传,通过七牛的回调,来判断上一张图片是否上传完成,上传完成了,再上传下一张图片。
好了,话不多说,贴代码:
1.压缩图片
/** * 质量压缩法 * * @param image * @return */ public byte[] compressImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中 int options = 100; while (baos.toByteArray().length / 1024 > 250) { //循环判断如果压缩后图片是否大于100kb,大于继续压缩 baos.reset();//重置baos即清空baos image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中 options -= 10;//每次都减少10 if (options <= 10) { break; } } byte[] byteArray = baos.toByteArray(); try { if (baos != null) { baos.close(); } } catch (IOException e) { e.printStackTrace(); } return byteArray; }
这个之前是压缩到100k的,这个没有按比例压缩,有的图片尺寸比较大的会模糊,所以现在调整到250k,估计压缩的图片大小会在200-300k左右吧。
2.递归上传图片
/** * 递归上传图片主要方法 * @param picUrl 图片的本地路径 * @param picSize 上传图片总数量 * //picNum是计数器,用于计算已上传图片的数目 * //snplMomentAddPhotos.getData().get(picNum)是选择图片的开源库,返回一个ArrayList<String>类型的图片路径 * BitmapUnit.getInstance().compressImage(BitmapUnit.getInstance().getBItmap(picUrl))//压缩图片 * */ private void upPic(String picUrl, int picSize) { //根据七牛上传图片的api,封装的上传方法 QiniuUtils.getInstance().uploadSmallFile(BitmapUnit.getInstance(). compressImage(BitmapUnit.getInstance().getBItmap(picUrl)), url -> { //图片成功上传到七牛时回调 //当前完成上传的图片数量小于总图片数量的时候重新调用该方法递归 if (picNum < picSize) { upPic(snplMomentAddPhotos.getData().get(picNum), picSize); Contants.upPicStatus = 1; if (loadingDialog != null) { loadingDialog.loadingStatus((picNum + 1) + "/" + picSize + "张图片"); } //拼接字符串 if (TextUtils.isEmpty(picUrls)) { picUrls = url; } else { picUrls = picUrls + "," + url; } }else { //结束递归 if (loadingDialog != null) { loadingDialog.dismiss(); } Contants.upPicStatus = 200; WorkManger.getInstance().publishWOrk("1", mClassTimetablesId, tvTitle.getText().toString(), etName.getText().toString(), picUrls, mCourseId); } picNum++;//添加计数器,这个要放到最后,不然会数组角标溢出 }); }
这个代码不难看懂,具体的都写在注释里面了,有一些是项目里面用到的,各位看官只要明确在哪里调用方法进行递归和在哪里添加计数器,在哪里结束递归就可以了。
但是这个方法有一点小瑕疵,正常我们在上传图片的过程中,都要有加载进度条,我发现加载进度条在每次上传成功的时候都会稍微卡一下。初步推断是因为压缩图片引起的,压缩图片的时候也是比较耗能的,而且同在主线程,会引起卡顿。提出的解决方案是:把图片压缩部分提出来,放在子线程中,先压缩图片,然后在同意上传。不过还没来的及优化,当然各位如果有什么好的想法,请提出来。感激不尽。