最近接了个私活,需要用到上传图片的功能,虽然是私活,但本着严谨负责的态度,还是想做到图片压缩的同时保证图片不失真,尽可能避免OOM的风险,个人用过的比较好用的图片压缩框架有两个,一个是LuBan,一个是Compressor.
LuBan的GitHub地址:https://github.com/Curzibn/Luban
Compressor的GitHub地址:https://github.com/zetbaitsu/Compressor
这里主要讲讲LuBan.load(uri)这个方法,一般上传图片都是从相册中获取或者直接调用相机拍摄返回,在onActivityResult()接收,由于拍照的时候一般会记录图片的绝对路径,所以用LuBan压缩的时候直接LuBan.load(String path)就好了,这个不多说,咱们主要说从相册中选择图片这块,一般选中图片后,用下边这段代码就可以直接把图片show出来:
Uri mUri = data.getData(); try { InputStream inputStream = getContentResolver().openInputStream(mUri); Bitmap bm = BitmapFactory.decodeStream(inputStream); imageView.setImageBitmap(bm); } catch (FileNotFoundException e) { e.printStackTrace(); }
那如果想压缩后再显示出来的话,代码是这样写的(这里用了Rxjava,看不懂的没关系,直接用官方的方式就行):
List<Uri> uriList = new ArrayList<>(); uriList.add(data.getData()); Flowable.just(uriList) .observeOn(Schedulers.io()) .map(new Function<List<String>, List<File>>() { @Override public List<File> apply(List<String> strings) throws Exception { return Luban.with(RegisterActivity.this).load(strings).get(); } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<List<File>>() { @Override public void accept(List<File> files) throws Exception { Bitmap bitmap = BitmapFactory.decodeFile(files.get(0).getAbsolutePath()); imageView.setImageBitmap(bitmap); } });
如果这样写,那问题就来了,在imageView.setImageBitmap(bitmap)时,bitmap为空,然后data.getData().getPath()也不行,不会提示压缩失败,会进到LuBan的success方法,百思不得其解的情况下,我只好转变图片路径,通过ContentResolver()方式去获取图片的绝对路径,改成如下代码即可:
Uri selectedImage = data.getData(); String[] filePathColumn = {MediaStore.Images.Media.DATA}; Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null); cursor.moveToFirst(); int columnIndex = cursor.getColumnIndex(filePathColumn[0]); String picturePath = cursor.getString(columnIndex); cursor.close(); List<String> uriList = new ArrayList<>(); uriList.add(picturePath); Flowable.just(uriList) .observeOn(Schedulers.io()) .map(new Function<List<String>, List<File>>() { @Override public List<File> apply(List<String> strings) throws Exception { return Luban.with(RegisterActivity.this).load(strings).get(); } }) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Consumer<List<File>>() { @Override public void accept(List<File> files) throws Exception { Bitmap bitmap = BitmapFactory.decodeFile(files.get(0).getAbsolutePath()); imageview.setImageBitmap(bitmap); } });
总结:LuBan.load(Uri uri)方法返回的File文件为空,所以在从相册中选择图片并压缩的时候,先用getContentResolver()方法查询返回的uri代表的图片在手机上的绝对路径再进行压缩,不能直接调用load(Uri uri)的方式