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視頻,壓的很差,見諒!

相關文章
相關標籤/搜索