Android仿微信无网络保存图片到相册,基于Glide4.x与Rxjava2.x

今天在微信预览大图时,发现其在无网络的状况下也能够保存图片,我以为这是个常见的需求,因此动手实现相似的需求,中间也踩了挺多坑,因此跟你们一块儿分享我踩过的坑。数组

知识点概览

一、Glide如何获取缓存的图片

二、Android文件的拷贝

三、保存的图片如何通知系统更新图库

=============分割线============缓存

一、Glide如何获取缓存的图片

Glide4.x如下,加载图片的方式为bash

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的方式也不一样app

Glide4.x如下获取的方法为ide

File file =  Glide.with(context)
        .load(imgUrl)
        .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
        .get();复制代码

Glide4.x以上时,为spa

File file = Glide.with(context)
        .download(imgUrl)
        .submit()
        .get();复制代码

二、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方法释放资源。code

三、保存的图片如何通知系统更新图库

咱们保存玩图片后,须要通知系统相册刷新,不然是找不到保存的图片的。

关于通知系统相册更新,有两种方法。

第一,直接发送广播

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<File>) 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视频,压的很差,见谅!

相关文章
相关标签/搜索