Bitmap bitmap = mBitmapLruCache.get(“1”);
ivBitamp.setImageBitmap(bitmap);
//删除缓存,一般不会用,因为快满时会自动删近期最少使用的缓存,就是它的核心功能
mBitmapLruCache.remove(“1”);
}
可见使用很简单,那么LruCache是怎么完成 删除“近期最少使用” 的呢?看下LruCache的代码:
public class LruCache<K, V> {
//此map以强引用的方式存储缓存对象
private final LinkedHashMap<K, V> map;
//当前缓存的大小(带单位的)
private int size;
//缓存最大容量(带单位的)
private int maxSize;
…
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException(“maxSize <= 0”);
}
this.maxSize = maxSize;
//LinkedHashMap是按照 访问顺序 排序的,所以get、put操作都会把要存的k-v放在队尾
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
/**
- 获取缓存,同时会把此k-v放在链表的尾部
*/
public final V get(K key) {
if (key == null) {
throw new NullPointerException(“key == null”);
}
V mapValue;
//get是线程安全的操作
synchronized (this) {
//LinkedHashMap的get方法中调afterNodeAccess,会移到链表尾部
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
…
}
/**
-
缓存key-value,value会存在 队尾
-
@return 之前也是这个key存的value
*/
public final V put(K key, V value) {
if (key == null || value == null) {
//不允许 null key、null value
throw new NullPointerException(“key == null || value == null”);
}
V previous;
//可见put操作是线程安全的
synchronized (this) {
putCount++;
size += safeSizeOf(key, value);
//强引用存入map(不会被动地被系统回收),其因为是LinkedHashMap,会放在队尾
previous = map.put(key, value);
if (previous != null) {
//如果前面已这个key,那么替换后调整下当前缓存大小
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, value);
}
//重新调整大小
trimToSize(maxSize);
return previous;
}
/**
- 比较 当前已缓存的大小 和最大容量,决定 是否删除
*/
private void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
- “.sizeOf() is reporting inconsistent results!”);
}
if (size <= maxSize) {
//大小还没超过最大值
break;
}
//已经达到最大容量
//因为是访问顺序,所以遍历的最后一个就是最近没有访问的,那么就可以删掉它了!
Map.Entry<K, V> toEvict = null;
for (Map.Entry<K, V> entry : map.entrySet()) {
toEvict = entry;
}
// END LAYOUTLIB CHANGE
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
//因为是为了腾出空间,所以这个回调第一个参数是true
entryRemoved(true, key, value, null);
}
}
protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
…
}
由以上代码及注释,可见LruCache的算法实现是依靠 设置了访问顺序的LinkedHashMap。因为是访问顺序模式,get、put操作都会调整k-v到链表尾部。在缓存将满时,遍历LinkedHashMap,因为是访问顺序模式,所以遍历的最后一个就是最近没有使用的,然后删除即可。
2.2 DiskLruCache
DiskLruCache是实现磁盘缓存,所以需要设备存储的读写权限;一般是从网络请求图片后缓存到磁盘中,所以还需要网络权限。
DiskLruCache,不是官方提供,所以需要引入依赖: