Android緩存之DiskLruCache(磁盤緩存)

DiskLruCache和LruCache不同的是,LruCache是內存緩存,而DiskLruCache是指磁盤緩存,顧名思義就是把文件緩存到磁盤,也也就是手機的內存卡中。接下來先簡單介紹DiskLruCache的使用方法。

下載源碼

DiskLruCache并沒有在 SDK中存在,但又是谷歌提倡的。所以我們要先把DiskLruCache的源碼下載下來。
我們可以通過下面這個地址下載源碼:
https://github.com/JakeWharton/DiskLruCache/tree/master/src/main/java/com/jakewharton/disklrucache
然后把源碼中的三個類拷貝到工程中。

初始化緩存對象

接下來具體介紹DiskLruCache的簡單方法。首先我們在使用某個類的時候,一般都是首先找到它的構造方法,但是我們發(fā)現(xiàn)該類是final 類,無法被繼承,并且構造方法是私有的方法,不能手動調用。

public final class DiskLruCache implements Closeable {

  private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
    this.directory = directory;
    this.appVersion = appVersion;
    this.journalFile = new File(directory, JOURNAL_FILE);
    this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP);
    this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP);
    this.valueCount = valueCount;
    this.maxSize = maxSize;
  }

所以在初始化DiskLruCache的時候調用它的open方法

 //四個參數(shù)分別為,1.緩存的路徑目錄 2.版本號 3.每個節(jié)點對應的數(shù)據(jù)個數(shù),4.緩存的大小,10 * 1024 * 1024 = 10M
            DiskLruCache diskLruCache = DiskLruCache.open(getCachFile(context, uniqueName), 1, 1, cacheSize);

/**
     * 獲取緩存目錄
     *
     * @param context
     * @param uniqueName 指定目錄下的文件名
     */
    private File getCachFile(Context context, String uniqueName) {
        String catchPath;
        //有內存卡,并且內存卡沒有正在移除,就把文件緩存到內存卡中
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) {
            catchPath = context.getExternalCacheDir().getPath();
        } else {
            catchPath = context.getCacheDir().getPath();
        }
        return new File(catchPath + File.separator + uniqueName);
    }

要傳入四個參數(shù):
File directory:sdcard緩存的目錄。
int appVersion:版本號,一般傳1即可
int valueCount:緩存的數(shù)據(jù)由key對應著,表示一個key對應多少個數(shù)據(jù),一般傳1即可
long maxSiz:緩存的大小 10 * 1024 * 1024 = 10M
傳入sdcard緩存的目錄的時候,記得先判斷sdcard是否存在,或者sdcard是否正在移除。如果是這兩種情況。緩存目錄就設置為getCacheDir().getPath();在內存中緩存。

寫入緩存

初始化緩存完成之后,就寫入緩存,這個時候需要從網(wǎng)上下載一張圖片。

new Thread() {
                    @Override
                    public void run() {
                        DiskLruCache.Editor editor = null;
                        try {
                            //創(chuàng)建 Editor 對象
                            editor = diskLruCache.edit(hashKeyForDisk(url));
                            if (editor != null) {
                                //創(chuàng)建輸出流
                                OutputStream outputStream = editor.newOutputStream(0);
                                //url 也就是 下載圖片的地址
                                //outputStream 的作用在于,
                                //從網(wǎng)絡下載圖片的時候,圖片通過該輸出流寫到文件系統(tǒng),
                                //也就是說,圖片下載到了磁盤緩存中。
                                if (downloadUrlToStream(url, outputStream)) {
                                    editor.commit();
                                } else {
                                    //釋放編輯鎖
                                    editor.abort();
                                }
                                diskLruCache.flush();
                            }

                        } catch (Exception e) {
                            e.printStackTrace();
                        }

                    }
                }.start();
 /**
     * 將key進行加密
     *
     * @param key
     * @return
     */
    public String hashKeyForDisk(String key) {
        String cacheKey;
        try {
            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
            mDigest.update(key.getBytes());
            cacheKey = bytesToHexString(mDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            cacheKey = String.valueOf(key.hashCode());
        }
        return cacheKey;
    }

    private String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }

我們首先初始化 DiskLruCache.Editor editor對象,把圖片的url經過MD5加密,然后作為緩存圖片的key。這里為什么不直接用url作為key而要進行md5加密呢。因為url中,可能存在一些特殊字符,這樣一來可能在命名文件的時候不合法。 md5加密之后的字符是唯一的,并且都是0-F的字符。然后創(chuàng)建OutputStream outputStream對象

OutputStream outputStream = editor.newOutputStream(0);

下載圖片之后就是通過該輸出流進行寫入文件,也就是說,把下載下來的圖片寫入到緩存目錄中。

 //也就是說,圖片下載到了磁盤緩存中。
                                if (downloadUrlToStream(url, outputStream)) {
                                    editor.commit();
                                } else {
                                    //釋放編輯鎖
                                    editor.abort();
                                }
                                diskLruCache.flush();

下載成功后調用 editor.commit();提交即可。
我們具體看下下載圖片的方法

/**
     * 從網(wǎng)絡中下載圖片,并寫到緩存中
     *
     * @param urlString
     * @param outputStream
     * @return
     */
    private boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
        HttpURLConnection urlConnection = null;
        BufferedOutputStream out = null;
        BufferedInputStream in = null;
        try {
            final URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();
            in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
            out = new BufferedOutputStream(outputStream, 8 * 1024);
            int b;
            while ((b = in.read()) != -1) {
                out.write(b);
            }
            return true;
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

我們看到下載的圖片寫到 OutputStream outputStream中,也就是寫到了緩存中。這樣一來就把圖片寫到了緩存中了。
我們看下緩存圖片的目錄:


image.png

我們看到這里有一個journal文件和一個名字很長的文件,名字很長的文件,就是我們的緩存文件了,因為是經過md5加密后的字符串。

讀取緩存

接下里我們介紹如何讀取緩存文件。

 DiskLruCache.Snapshot snapshot = diskLruCache.get(hashKeyForDisk(url));
                if(snapshot!=null){
                    InputStream inputStream = snapshot.getInputStream(0);
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    //如果不為空,則直接展示緩存中的bitmap
                    imageView.setImageBitmap(bitmap);  
                }

這里為什么是getInputStream(0);呢。因為我們上面定義了一個key對應一個數(shù)據(jù),所以只獲取第0個即可
我們看下運行的效果圖:

image.png

移除緩存

調用remove方法,移除指定的數(shù)據(jù)。

  public synchronized boolean remove(String key) throws IOException 

其他api

1.flush()
用于將內存中的操作記錄同步到日志文件,也就是sdcard中的journal文件。DiskLruCache正常工作就要依賴該文件中的內容。但是沒必要每次寫入緩存操作的時候都調用一次,一般在Activity的onPause方法中調用一次即可。
2.delete()
刪除所有的緩存

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容