Android UIL缓存(Android-Universal-Image-Loader)缓存部分的源码解析

一篇迟到的博客吧,这边博客应该两年前都写了,一直推迟到今天

这里只介绍几种缓存策略的实现。

UsingFreqLimitedMemoryCache 缓存满时 清除使用次数最少的

LRULimitedMemoryCache 缓存满时清除最近最不长使用的

LargestLimitedMemoryCache 缓存满了清除最大的缓存

FIFOLimitedMemoryCache缓存满时清除最先加入的

LimitedAgeMemoryCache 已经过期的缓存进行清理,并且重新请求。

这些策略到底是如何实现的那。

他们的最上层的父类是 MemoryCache

public interface MemoryCache {
添加

boolean put(String key, Bitmap value);

获取

Bitmap get(String key);

移除

Bitmap remove(String key);

所有图片的KEY,这里是对每个Bitmap的唯一性标示

Collection<String> keys()

}

在上层的抽象类是BaseMemoryCache

里面提供了对 bitmap的存储,使用的是 hashMap,这样可以更高效的对图片流进行存取。并且对图片进行了软引用。

在上层是LimitedMemoryCache 这个类是对 开始在application里面设置的 缓存大小参数和使用测试参数的阈值,以便于执行romve的操作 并且加了两个抽象方法

protected abstract int getSize(Bitmap value); //获取图片的大小

protected abstract Bitmap removeNext();//移除下一个


这里有两个参数很重要 ,sizeLimit 最大库存大小,chachSize 是个原子累加器,在多线程的操作也是安全的,存储可缓存的大小。sizeLimit 超过这个大小就不会存在hardCache缓存中,并且也不会累加大小,sizeLimit初始值是在application中设置的值,

chachSize用来记录当前已经存储的大小,当chachSize>sizeLimit时,会调用 removeNext(),这里是调用的抽象方法,每个实现类都有自己的实现。

public boolean put(String key, Bitmap value) {

boolean putSuccessfully = false;
int valueSize = getSize(value); //getSize()是抽象方法,每个实现方法有自己的实现。
int sizeLimit = getSizeLimit();
int curCacheSize = cacheSize.get();//获取当前cacheSize类的值(是原子操作,不存在并发问题)
if (valueSize < sizeLimit) {
while (curCacheSize + valueSize > sizeLimit) { //循环直到当前值可以存储进去之后再进行移出
Bitmap removedValue = removeNext(); //用于减少下一个
if (hardCache.remove(removedValue)) { //从hardCache中移出 如果成功就减去大小
curCacheSize = cacheSize.addAndGet(-getSize(removedValue)); //减去cacheSize的大小
}
}
hardCache.add(value);
cacheSize.addAndGet(valueSize);


putSuccessfully = true;
}
// Add value to soft cache
super.put(key, value);
return putSuccessfully;
}


现在已经找到了 MemoryCache 在哪里移出的缓存对象。

具体的移出操作是 在每次添加的是,就去计算下有没有超过初始化的时候设定的大小,如果超过就执行移出操作,直到当前大小,小于设定的大小减去要添加缓存的大小时停止,如果没有那就执行添加操作。

 那就看具体的实现类是怎么操作的就可以。

现在我们只看这些类的Remove操作就可以了。

UsingFreqLimitedMemoryCache  当缓存满了之后移出使用次数最少的。

看下源码是如何操作的。

源码第 46行有一个初始的Map;

private final Map<Bitmap, Integer> usingCounts = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());

usingCounts 用户使用计数,这个map是用来存储,每次使用Bitmap对象,就会对当前的bitmap对象进行加1的操作,

看下具体的代码实现。


put方法,if(super.put(key, value)) putSuccessfully在添加成功的时候返回true在 失败返回false。添加成功是指 添加到hardcache中的,或者value的地址不相同。true之后在usingCounts添加一条数据。

再看下如何叠加的


每次获取,获取到不为空的value,就会叠加1.这样就记录了每次读取+1.以便于我们使用remove的时候去移除。


每次调用remove()方法。为了出现多线程操作导致usingCounts有其他线程在做添加或者remove的操作。导致循环报错(modeCount)会改变。每次循环找到最小的UsageCount,然后找到对应的key值,去做remove的操作。这样就做到了当缓存满的时候。使用次数最少的。

LRULimitedMemoryCache 清除最近最不长使用的。

看下他的存储结构

private final Map<String, Bitmap> lruCache = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(INITIAL_CAPACITY, LOAD_FACTOR, true));

Collections.synchronizedMap 这里是返回一个多线程操作安全的 map .

选择的是LinkedHashMap 并且是选择的带构造参数的。这里的参数就有意思了。


第一个是初始化的大小,第二个是,阈值参数,第三个是重点,这个参数如果设置成true。

LinkedHashMap是有序的map。设置成true以后所有的key值就按照你的输入顺序进行排序。如果之后输入的之前已经有的key值,那么之前的会被移除掉,添加到最后面,比如 我输入 (1,1),(2,2)(3,3)。key的顺序是 1,2,3。然后我在输入或者get (1,1),那么key的顺序是 2,3,1。

这样的话每次使用就给你的key做了一次排序记录。

了解到这些在看下源码就好。


put中每次使用每次添加一下。会从新key排序。

那就看下remove的代码。


会按照链表的顺序移除,先移除最左侧的。

FIFOLimitedMemoryCache 先进先出 删除最先入栈的。

他使用的存储器是

private final List<Bitmap> queue = Collections.synchronizedList(new LinkedList<Bitmap>());

会按照你的加入的顺序进行排序removeNext 的方法也很简单就是移除第一个。

protected Bitmap removeNext() {
return queue.remove(0);

}

LargestLimitedMemoryCache 内存满后,移除缓存中最大的对象。

存储器是 private final Map<Bitmap, Integer> valueSizes = Collections.synchronizedMap(new HashMap<Bitmap, Integer>());

就是个hashMap 进行存储缓存。


移除代码就是循环移除里面最大的bitmap对象。

LimitedAgeMemoryCache 设置超时时间,当缓存超过自己的设置的时间,就不再去使用他,并且移除他。


这些缓存,每次先执行的应该是get方法,再是put方法。因为每次都要先在缓存中拿,然后再从网络进行获取。

为什么要看这些缓存策略,一个好的缓存框架大概可以分为两个部分,第一个是网络请求。第二个是缓存,当然也包括固化到本地硬盘当中。在移动端的开发中,放你把缓存写好了,你就可以写非图片的缓存,比如我之前的做的项目,缓存mp3,缓存txt文本内容,文本路径。这样的给用户带来的感官就是,APP反应比较快。对服务器也能减轻压力,取消掉不必要的请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值