Android图片压缩上传(整体压缩VS单张压缩)
Posted 亮亮在江湖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android图片压缩上传(整体压缩VS单张压缩)相关的知识,希望对你有一定的参考价值。
最近的项目中图片上传时遇到了anr的情况,下面看一下bugly上的错误
主要说的是图片上传多张时先进行压缩,此时压缩超时,上报anr,针对这种情况采取了遍历图片集合单张上传,接下来会逐一介绍整体上传和单张上传的代码部分,下面两张gif图是展示单张和整体上传的效果。
单张压缩上传 整体压缩上传
da
首先项目中添加所需要的依赖,图片选择器采用的是matisse,像朋友圈一样多张图片选择器,加载图片框架采用的是glide,网络框架是retrofit。
implementation 'com.zhihu.android:matisse:0.5.3-beta3'
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
先来说一下整体压缩的主要代码,点击整体压缩按钮跳转到图片选择器页面,最多可以上传9张图片,其中uploadSumImg代表已上传的图片数量,最多设置为
.maxSelectablePerMediaType(9 - uploadSumImg, 1)
public void openPic()
if (uploadSumImg < 9)
Matisse.from(MoreUploadActivity.this)
.choose(MimeType.ofImage(), false)
.countable(true)
.capture(true)
.captureStrategy(new CaptureStrategy(true, BuildConfig.APPLICATION_ID+".fileprovider"))
.maxSelectablePerMediaType(9 - uploadSumImg, 1)
.gridExpectedSize(getResources().getDimensionPixelSize(R.dimen.grid_expected_size))
.addFilter((new util.GifSizeFilter(0, 0, 10 * Filter.K * Filter.K)))
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
.thumbnailScale(0.85f)
.theme(R.style.Matisse_Dracula)//主题 暗色主题
.imageEngine(new GlideEngine())
.showSingleMediaType(true)
.maxOriginalSize(10)
.autoHideToolbarOnSingleTap(true)
.forResult(23);
选择完对应的图片确定后回调事件获取本地图片路径集合
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data)
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 23 && resultCode == RESULT_OK && data != null)
List<String> pathList = Matisse.obtainPathResult(data);
List<Uri> uriList = Matisse.obtainResult(data);
util.LoadingDialog.showDialog(this);
if (uriList.size() > 0)
new Handler().postDelayed(() -> handleImage(uriList,pathList), 200);
/**
* 处理要添加的图片
*/
private void handleImage(List<Uri> list, List<String> pathList)
String path = null;
images.clear();
for (int i = 0; i < list.size(); i++)
Uri uri = list.get(i);
//根据不同的uri进行不同的解析
if (DocumentsContract.isDocumentUri(this, uri))
String docId = DocumentsContract.getDocumentId(uri);
if ("com.android.providers.media.documents".equals(uri.getAuthority()))
String id = docId.split(":")[1];
String selection = MediaStore.Images.Media._ID + "=" + id;
path = util.BusinessUtils.getImagePath(this,MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection);
else if ("com.android.providers.downloads.documents".equals(uri.getAuthority()))
Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId));
path = util.BusinessUtils.getImagePath(this,contentUri, null);
else if ("content".equalsIgnoreCase(uri.getScheme()))
path = util.FileUtil.getFilePathFromURI(this, uri);
else if ("file".equalsIgnoreCase(uri.getScheme()))
path = uri.getPath();
images.add(new UploadImageBean(pathList.get(i), path));
if (images.size() > 0)
uploadPicture(images);
此时将获取到的图片循环压缩,先尺寸压缩再进行质量压缩
public static String getCompressImage(String srcPath, int maxSize, String outputName)
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
//此时返回bm为空
Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts);
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
//现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
int hh,ww;
if (getFileSize(new File(srcPath)) / 1024 > maxSize)
if (w >= 3000 && h >= 3000)
if(w>=h)
hh = 2500;
ww = 2501;
else
hh = 2500;
ww = 2500;
else
hh = dm.heightPixels;
ww = dm.widthPixels;
else
hh = h;
ww = w;
// float hh = 800f;//这里设置高度为800f
// float ww = 480f;//这里设置宽度为480f
//缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
int be = 1;//be=1表示不缩放
if (w > h && w > ww) //如果宽度大的话根据宽度固定大小缩放
be =Math.round ((float) newOpts.outWidth / ww);
else if (w < h && h > hh) //如果高度高的话根据宽度固定大小缩放
be = Math.round((float) newOpts.outHeight / hh);
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;//设置缩放比例
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
int degree = readPictureDegree(srcPath);
bitmap = rotateBitmap(bitmap, degree);
bitmap = qualityCompressImage(bitmap, maxSize);//压缩好比例大小后再进行质量压缩
String path = saveBitmap(outputName,bitmap);
if(bitmap!=null)
bitmap.recycle();
return path;
调用上传接口,获取到后台返回的图片集合,设置成功后绘制在页面
//图片上传
Call<ResponseImgBean> uploadResultCall = RetrofitBuild.getAnInterface().uploadImage(parts);
uploadResultCall.enqueue(new Callback<ResponseImgBean>()
@Override
public void onResponse(Call<ResponseImgBean> call, Response<ResponseImgBean> response)
util.LoadingDialog.dismissDialog();
if(response.body().isSuccess())
List<String> urls = response.body().getData();
List<ImageBean> beans = new ArrayList<>();
for(int i = 0;i<urls.size();i++)
ImageBean bean = new ImageBean();
File file ;
if (images.get(i).isGif())
file = new File(images.get(i).getRealPath());
else
file = new File(Environment.getExternalStorageDirectory(), "boxCompress" + i + ".jpg");
List<Integer> size = util.BitmapUtils.getImageSize(file.getAbsolutePath());
bean.setUrl(urls.get(i));
bean.setWidth(size.get(0));
bean.setHeight(size.get(1));
if(!images.get(i).isGif()&&file.exists())
file.delete();
beans.add(bean);
if (beans.size() != images.size())
Toast.makeText(MoreUploadActivity.this,"上传图片失败",Toast.LENGTH_SHORT).show();
return;
else
for (int i = 0; i < beans.size(); i++)
beans.get(i).setPath(images.get(i).getUriPath());
imageEditor.addImage(beans);
images.clear();
else
Toast.makeText(MoreUploadActivity.this,"上传图片失败",Toast.LENGTH_SHORT).show();
@Override
public void onFailure(Call<ResponseImgBean> call, Throwable t)
Toast.makeText(MoreUploadActivity.this,"上传图片失败",Toast.LENGTH_SHORT).show();
util.LoadingDialog.dismissDialog();
);
第二种采取单张压缩上传,用同样的方式获取到本地图片的路径集合,然后采用单独压缩
//图片压缩
private void checkImage()
UploadImageBean uploadImageBean = imageList.get(0);
if (uploadImageBean.isGif())
uploadPicture(uploadImageBean.getRealPath());
else
util.ImageCompressTask compressTask = new util.ImageCompressTask(new util.ImageCompressTask.CompressListener()
@Override
public void Success(String imagePath)
uploadPicture(imagePath);
);
compressTask.execute(uploadImageBean.getUriPath(), "boxCompress" + 0 + ".jpg");
public static class ImageCompressTask extends AsyncTask<String, Integer, String>
private final CompressListener compressListener;
public ImageCompressTask(CompressListener listener)
compressListener = listener;
@Override
protected String doInBackground(String... strings)
String imagePath = strings[0];
String outputName = strings[1];
return BitmapUtils.getCompressImage(imagePath, 1024, outputName);
@Override
protected void onPostExecute(String path)
if(compressListener != null)
compressListener.Success(path);
public static interface CompressListener
void Success(String imagePath);
最后调用图片上传接口,
//图片上传
private void uploadPicture(String path)
List<MultipartBody.Part> parts = new ArrayList<>();
File file = new File(path);
RequestBody fileRQ = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBody.Part part = MultipartBody.Part.createFormData("files", file.getName(), fileRQ);
parts.add(part);
Call<ResponseImgBean> uploadResultCall = RetrofitBuild.getAnInterface().uploadImage(parts);
uploadResultCall.enqueue(new Callback<ResponseImgBean>()
@Override
public void onResponse(Call<ResponseImgBean> call, Response<ResponseImgBean> response)
if(response.body().isSuccess())
List<String> urls = response.body().getData();
List<ImageBean> beans = new ArrayList<>();
ImageBean bean = new ImageBean();
File file;
if (imageList.get(0).isGif())
file = new File(imageList.get(0).getRealPath());
else
file = new File(Environment.getExternalStorageDirectory(), "boxCompress" + 0 + ".jpg");
List<Integer> size = util.BitmapUtils.getImageSize(file.getAbsolutePath());
bean.setUrl(urls.get(0));
bean.setWidth(size.get(0));
bean.setHeight(size.get(1));
if (!imageList.get(0).isGif() && file.exists())
file.delete();
beans.add(bean);
imageList.remove(0);
if(beans != null)
beans.get(0).setPath(images.get(0).getUriPath());
imageEditor.addImage(beans);
images.remove(0);
if (imageList.size() == 0)
util.LoadingDialog.dismissDialog();
else
checkImage();
else
util.LoadingDialog.dismissDialog();
Toast.makeText(SingleUploadActivity.this,"上传图片失败",Toast.LENGTH_SHORT).show();
@Override
public void onFailure(Call<ResponseImgBean> call, Throwable t)
Toast.makeText(SingleUploadActivity.this,"上传图片失败",Toast.LENGTH_SHORT).show();
imageList.remove(0);
images.remove(0);
if(imageList.size()>0)
checkImage();
else
util.LoadingDialog.dismissDialog();
);
imageList为要上传的图片集合,每一张图片上传成功后移除调首位置的图片imageList.remove(0);
如果移除不是最后一个,那么重新调用图片压缩上传,直到最后结束。
if (imageList.size() == 0)
util.LoadingDialog.dismissDialog();
else
checkImage();
到这里图片的两种压缩上传方式也讲完了,希望本文对有需要的同学帮助,欢迎讨论。最后附上本文的demo 代码下载
以上是关于Android图片压缩上传(整体压缩VS单张压缩)的主要内容,如果未能解决你的问题,请参考以下文章