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  代码下载

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值