图片加载UIL的Disk缓存策略

统一接口interface DiskCache
缓存策略有
1.0.0版本出现 UnlimitedDiskCache
1.3.1版本出现 LimitedAgeDiskCache:
1.9.2版本出现 LruDiskCache 在ext扩展包下面
其中UnlimitedDiskCache是默认的缓存模式
UnlimitedDiskCacheLimitedAgeDiskCache都是继承自BaseDiskCache,而BaseDiskCache是一个抽象类,她实现了DiskCache接口,完成了保存,移除等基本操作
LruDiskCache是后来扩展的,直接实现了DiskCache

先说说保存文件名如何生成的吧!这个名字一定要是唯一的,不能重复!
算法相当重要,这里一共提供了MD5和HashCode

  1. HashCodeFileNameGenerator
  2. Md5FileNameGenerator
    统一实现了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做进制转换,看着有点懵逼!我做个测试
如果我的地址是 http://www.jianshu.com
new String(md5)结果是(乱码) ���v�A�'[f��R�)�
bi.toString() 结果是 94697506358415651344405842152910083822
bi.toString(10 + 26) 结果是 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个构造方法

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);
}

第二个参数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修改最近一次的时间,然后把文件和时间缓存到内存里,方便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;
    }

先读文件,判断文件是否存在,如果存在,从内存里取出上次文件的修改时间,如果时间内存中没有,就直接读File的属性,然后通过与当前的时间做比对,如果过期了,就把文件删掉,索引也从内存中移除掉,否则有效,直接返回文件!

3.LruDiskCache

基于传说中的"Least-Recently Used",也即是近期最少使用算法,它是一个适配器,它适配了另一个关键类DiskLruCache,这个是硬盘存储的cache的类,它是square公司大神JakeWharton的一个项目
https://github.com/JakeWharton/DiskLruCache

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

默认是按插入顺序排序,如果指定访问顺序排序,那么调用get方法后,会将这次访问的元素移至链表尾部,不断访问可以形成按访问顺序排序的链表。 可以重写removeEldestEntry方法返回true值指定插入元素时移除最老的元素。

有一次看动脑学院的讲打造牛逼的图片缓存框架也就就是针对这个集合做一些基础操作,达到磁盘缓存...
DiskLruCache的详细分析,网上有很多相关文章,我这里找了一篇
http://blog.csdn.net/guolin_blog/article/details/28863651
UIL中LruDiskCache适配了DiskLruCache,在构造方法中初始化缓存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文件
每当我们调用一次DiskLruCache的edit()方法时,都会向journal文件中写入一条DIRTY记录,表示我们正准备写入一条缓存数据,但不知结果如何。然后,调用commit()方法表示写入缓存成功,这时会向journal中写入一条CLEAN记录,意味着这条“脏”数据被“洗干净了”,调用abort()方法表示写入缓存失败,这时会向journal中写入一条REMOVE记录。
也就是说,每一行DIRTY的key,后面都应该有一行对应的CLEAN或者REMOVE的记录,否则这条数据就是“脏”的,会被自动删除掉。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,306评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,657评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,928评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,688评论 0 220
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,105评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,024评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,159评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,937评论 0 212
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,689评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,851评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,325评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,651评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,364评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,192评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,985评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,154评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,955评论 2 279

推荐阅读更多精彩内容