圖片加載UIL的Disk緩存策略

統(tǒng)一接口interface DiskCache
緩存策略有
1.0.0版本出現(xiàn) UnlimitedDiskCache
1.3.1版本出現(xiàn) LimitedAgeDiskCache:
1.9.2版本出現(xiàn) LruDiskCache 在ext擴展包下面
其中UnlimitedDiskCache是默認的緩存模式
UnlimitedDiskCacheLimitedAgeDiskCache都是繼承自BaseDiskCache,而BaseDiskCache是一個抽象類,她實現(xiàn)了DiskCache接口,完成了保存,移除等基本操作
LruDiskCache是后來擴展的,直接實現(xiàn)了DiskCache

先說說保存文件名如何生成的吧!這個名字一定要是唯一的,不能重復!
算法相當重要,這里一共提供了MD5和HashCode

  1. HashCodeFileNameGenerator
  2. Md5FileNameGenerator
    統(tǒng)一實現(xiàn)了FileNameGenerator接口
public class HashCodeFileNameGenerator implements FileNameGenerator {
    @Override
    public String generate(String imageUri) {
        return String.valueOf(imageUri.hashCode());
    }
}

直接取hashCode()

public class Md5FileNameGenerator implements FileNameGenerator {

    private static final String HASH_ALGORITHM = "MD5";
    private static final int RADIX = 10 + 26; // 10 digits + 26 letters

    @Override
    public String generate(String imageUri) {
        byte[] md5 = getMD5(imageUri.getBytes());
        BigInteger bi = new BigInteger(md5).abs();
        return bi.toString(RADIX);
    }

    private byte[] getMD5(byte[] data) {
        byte[] hash = null;
        try {
            MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
            digest.update(data);
            hash = digest.digest();
        } catch (NoSuchAlgorithmException e) {
            L.e(e);
        }
        return hash;
    }
}

這里先是通過MD5做摘要算法,然后通過BigInteger做進制轉(zhuǎn)換,看著有點懵逼!我做個測試
如果我的地址是 http://www.reibang.com
new String(md5)結(jié)果是(亂碼) ???v?A?'[f??R?)?
bi.toString() 結(jié)果是 94697506358415651344405842152910083822
bi.toString(10 + 26) 結(jié)果是 47u6apm4arcy3jl456iglawa6

仔細想想,這里10 + 26代表0-9 A-Z 一共36個字符,平常用的最多的16進制,16進指最大是F代表15,這里為了降低文件名的長度,所以將進制用最大值,Z代表35, radix的范圍是MIN_RADIX~MAX_RADIX

MIN_RADIX = 2
MAX_RADIX = 36

這下明白了代碼用意

1.UnlimitedDiskCache

該模式,Cache緩存是無線增長的
代碼比較簡單,僅僅是3個構(gòu)造方法

public UnlimitedDiskCache(File cacheDir) {
        super(cacheDir);
}
public UnlimitedDiskCache(File cacheDir, File reserveCacheDir) {
        super(cacheDir, reserveCacheDir);
}
public UnlimitedDiskCache(File cacheDir, File reserveCacheDir, FileNameGenerator fileNameGenerator) {
        super(cacheDir, reserveCacheDir, fileNameGenerator);
}

第二個參數(shù)Reserve directory是儲備目錄,也就是主目錄不可用的情況下,會用這個目錄,心思極恐啊

2.LimitedAgeDiskCache

有期限的緩存,也就是當超過了自定義的時間時,緩存就刪除,這就想Cookie的MaxAge一樣,如果到期了Cookie就失效了!
核心代碼

private void rememberUsage(String imageUri) {
        File file = getFile(imageUri);
        long currentTime = System.currentTimeMillis();
        file.setLastModified(currentTime);
        loadingDates.put(file, currentTime);
    }

每次保存一個bitmap,就把那個文件setLastModified修改最近一次的時間,然后把文件和時間緩存到內(nèi)存里,方便get取操作
好,接著看下取操作

    @Override
    public File get(String imageUri) {
        File file = super.get(imageUri);
        if (file != null && file.exists()) {
            boolean cached;
            Long loadingDate = loadingDates.get(file);
            if (loadingDate == null) {
                cached = false;
                loadingDate = file.lastModified();
            } else {
                cached = true;
            }

            if (System.currentTimeMillis() - loadingDate > maxFileAge) {
                file.delete();
                loadingDates.remove(file);
            } else if (!cached) {
                loadingDates.put(file, loadingDate);
            }
        }
        return file;
    }

先讀文件,判斷文件是否存在,如果存在,從內(nèi)存里取出上次文件的修改時間,如果時間內(nèi)存中沒有,就直接讀File的屬性,然后通過與當前的時間做比對,如果過期了,就把文件刪掉,索引也從內(nèi)存中移除掉,否則有效,直接返回文件!

3.LruDiskCache

基于傳說中的"Least-Recently Used",也即是近期最少使用算法,它是一個適配器,它適配了另一個關(guān)鍵類DiskLruCache,這個是硬盤存儲的cache的類,它是square公司大神JakeWharton的一個項目
https://github.com/JakeWharton/DiskLruCache

DiskLruCache基于
LinkedHashMap<String, Entry> lruEntries = new LinkedHashMap<String, Entry>(0, 0.75f, true);
核心思想:

默認是按插入順序排序拳恋,如果指定訪問順序排序介杆,那么調(diào)用get方法后焊刹,會將這次訪問的元素移至鏈表尾部擎值,不斷訪問可以形成按訪問順序排序的鏈表晾浴。 可以重寫removeEldestEntry方法返回true值指定插入元素時移除最老的元素眉抬。

有一次看動腦學院的講打造牛逼的圖片緩存框架也就就是針對這個集合做一些基礎(chǔ)操作,達到磁盤緩存...
DiskLruCache的詳細分析,網(wǎng)上有很多相關(guān)文章,我這里找了一篇
http://blog.csdn.net/guolin_blog/article/details/28863651
UIL中LruDiskCache適配了DiskLruCache,在構(gòu)造方法中初始化緩存DiskLruCache實例

cache = DiskLruCache.open(cacheDir, 1, 1, cacheMaxSize, cacheMaxFileCount);

cacheMaxSize如果不指定的話,就取Long.MAX_VALUE最大值0x7FFFFFFFFFFFFFFFL

通過DiskLruCache.Editor緩存文件

public boolean save(String imageUri, Bitmap bitmap) throws IOException {
        DiskLruCache.Editor editor = cache.edit(getKey(imageUri));
        if (editor == null) {
            return false;
        }

        OutputStream os = new BufferedOutputStream(editor.newOutputStream(0), bufferSize);
        boolean savedSuccessfully = false;
        try {
            savedSuccessfully = bitmap.compress(compressFormat, compressQuality, os);
        } finally {
            IoUtils.closeSilently(os);
        }
        if (savedSuccessfully) {
            editor.commit();
        } else {
            editor.abort();
        }
        return savedSuccessfully;
    }

有點像SharedPreference,緩存key是用文件名生成器生成的,默認bitmap壓縮格式是PNG,然后移除,讀取都是i依賴key

DiskLruCache有一個journal文件
每當我們調(diào)用一次DiskLruCache的edit()方法時儡嘶,都會向journal文件中寫入一條DIRTY記錄张峰,表示我們正準備寫入一條緩存數(shù)據(jù),但不知結(jié)果如何堪簿。然后痊乾,調(diào)用commit()方法表示寫入緩存成功,這時會向journal中寫入一條CLEAN記錄椭更,意味著這條“臟”數(shù)據(jù)被“洗干凈了”靴寂,調(diào)用abort()方法表示寫入緩存失敗,這時會向journal中寫入一條REMOVE記錄摆屯。
也就是說敌厘,每一行DIRTY的key,后面都應該有一行對應的CLEAN或者REMOVE的記錄舌狗,否則這條數(shù)據(jù)就是“臟”的叽奥,會被自動刪除掉。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痛侍,一起剝皮案震驚了整個濱河市朝氓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖赵哲,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件待德,死亡現(xiàn)場離奇詭異,居然都是意外死亡枫夺,警方通過查閱死者的電腦和手機将宪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來筷屡,“玉大人涧偷,你說我怎么就攤上這事”兴溃” “怎么了燎潮?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長扼倘。 經(jīng)常有香客問我确封,道長,這世上最難降的妖魔是什么再菊? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任爪喘,我火速辦了婚禮,結(jié)果婚禮上纠拔,老公的妹妹穿的比我還像新娘秉剑。我一直安慰自己,他們只是感情好稠诲,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布侦鹏。 她就那樣靜靜地躺著,像睡著了一般臀叙。 火紅的嫁衣襯著肌膚如雪略水。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天劝萤,我揣著相機與錄音渊涝,去河邊找鬼。 笑死床嫌,一個胖子當著我的面吹牛跨释,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播厌处,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼煤傍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了嘱蛋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎洒敏,沒想到半個月后龄恋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡凶伙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年郭毕,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片函荣。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡显押,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出傻挂,到底是詐尸還是另有隱情乘碑,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布金拒,位于F島的核電站兽肤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏绪抛。R本人自食惡果不足惜资铡,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望幢码。 院中可真熱鬧笤休,春花似錦、人聲如沸症副。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瓦糕。三九已至底洗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間咕娄,已是汗流浹背亥揖。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留圣勒,地道東北人费变。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像圣贸,于是被迫代替她去往敵國和親挚歧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容