今天在微信预览大图时,发现其在无网络的情况下也可以保存图片,我觉得这是个常见的需求,所以动手实现类似的需求,中间也踩了挺多坑,所以跟大家一起分享我踩过的坑。
知识点概览
1、Glide如何获取缓存的图片
2、Android文件的拷贝
3、保存的图片如何通知系统更新图库
=============分割线============
1、Glide如何获取缓存的图片
Glide4.x以下,加载图片的方式为
Glide.with(context)
.load(obj)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView);复制代码
Glide4.x以上时,为
RequestOptions requestOptions = new RequestOptions()
.centerCrop()
.dontAnimate()
.diskCacheStrategy(DiskCacheStrategy.ALL);
Glide.with(context)
.load(obj)
.apply(requestOptions)
.into(iv);复制代码
这里有个注意点,diskCacheStrategy方法的缓存策略需要指定为DiskCacheStrategy.ALL或者DiskCacheStrategy.SOURCE,如果指定的缓存策略为DiskCacheStrategy.NONE,是获取不到缓存图的。
我们首先需要获取缓存的File,Glide因为版本不同,获取File的方式也不同
Glide4.x以下获取的方法为
File file = Glide.with(context)
.load(imgUrl)
.downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get();复制代码
Glide4.x以上时,为
File file = Glide.with(context)
.download(imgUrl)
.submit()
.get();复制代码
2、Android文件的拷贝
获得File后,这只是个文件,存在系统data目录下,我们需要将File复制到sd卡的目录下,并重命名为.jpg文件。
复制代码
String fileParentPath =
Environment.getExternalStorageDirectory().getAbsolutePath() + "/XingTu/Image";
File appDir = new File(fileParentPath);
if (!appDir.exists()) {
appDir.mkdirs();
}
//获得原文件流
FileInputStream fis = new FileInputStream(file);
//保存的文件名
String fileName = "xt" + System.currentTimeMillis() + ".jpg";
//目标文件
File targetFile = new File(appDir, fileName);
//输出文件流
FileOutputStream fos = new FileOutputStream(targetFile);
// 缓冲数组
byte[] b = new byte[1024 * 8];
while (fis.read(b) != -1) {
fos.write(b);
}
fos.flush();
fis.close();
fos.close();复制代码
首先创建要保存路径的文件appDir,然后创建目标文件targetFile,接着创建输入输出流,通过while循环输出文件,最后别忘了调用flush和close方法释放资源。
3、保存的图片如何通知系统更新图库
我们保存玩图片后,需要通知系统相册刷新,否则是找不到保存的图片的。
关于通知系统相册更新,有两种方法。
第一,直接发送广播
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
context.sendBroadcast(intent);复制代码
第二,使用MediaScannerConnection
//扫描媒体库
String extension = MimeTypeMap.getFileExtensionFromUrl(targetFile.getAbsolutePath());
String mimeTypes = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
MediaScannerConnection.scanFile(context, new String[]{targetFile.getAbsolutePath()},
new String[]{mimeTypes},null);复制代码
上面两种方法都能达到更新效果,但是查看了其他博客,有人说第一种方法某些情况下无效,具体我没有深究,这里推荐使用第二种方法更新。
完整代码
public void saveImgToGallery(final Context context, final String imgUrl){
Observable.create((ObservableOnSubscribe) emitter -> {
//Glide提供了一个download() 接口来获取缓存的图片文件,
// 但是前提必须要设置diskCacheStrategy方法的缓存策略为
// DiskCacheStrategy.ALL或者DiskCacheStrategy.SOURCE,
// 还有download()方法需要在子线程里进行
File file = Glide.with(context)
.download(imgUrl)
.submit()
.get();
String fileParentPath =
Environment.getExternalStorageDirectory().getAbsolutePath() + "/XingTu/Image";
File appDir = new File(fileParentPath);
if (!appDir.exists()) {
appDir.mkdirs();
}
//获得原文件流
FileInputStream fis = new FileInputStream(file);
//保存的文件名
String fileName = "xt" + System.currentTimeMillis() + ".jpg";
//目标文件
File targetFile = new File(appDir, fileName);
//输出文件流
FileOutputStream fos = new FileOutputStream(targetFile);
// 缓冲数组
byte[] b = new byte[1024 * 8];
while (fis.read(b) != -1) {
fos.write(b);
}
fos.flush();
fis.close();
fos.close();
//扫描媒体库
String extension = MimeTypeMap.getFileExtensionFromUrl(targetFile.getAbsolutePath());
String mimeTypes = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
MediaScannerConnection.scanFile(context, new String[]{targetFile.getAbsolutePath()},
new String[]{mimeTypes},null);
emitter.onNext(targetFile);
})
.subscribeOn(Schedulers.io()) //发送事件在io线程
.observeOn(AndroidSchedulers.mainThread())//最后切换主线程提示结果
.subscribe(file -> ToastUtil.showToast("保存图片成功"),
throwable -> ToastUtil.showToast("保存失败"));
}复制代码
总结:这是一个常见的需求,虽然代码很短,但是涉及到三个大的知识点,需要注重平常的积累,在遇到问题时首先冷静思考,而不是心里mmp,这样才能有效解决问题。
第一次写博客,如果有不对的地方欢迎一起交流。
最后放一个操作的gif视频,压的不好,见谅!