常用的三级缓存主要有LruCache、DiskLruCache、网络,其中LruCache对应内存缓存、DiskLruCache对应持久化缓存。Lru表示最近最少使用,意思是当缓存到达限制时候,优先淘汰近期内最少使用的缓存,LruCache和DisLruCache都是如此。
比如说Android中常来缓存Bitmap,我们先依次从LruCache、DiskLruCache获取,最后才网络下载。
本篇主要从原理和源码分析LruCache和DiskLruCache
LruCache
LruCache<K, V> 可以在内存中缓存数据,内部使用最近最少使用算法,优先淘汰最近时间内最少次使用的缓存对象。
LruCache使用
LruCache<String, Bitmap> mMemoryCache;
mMemoryCache = new LruCache<String, Bitmap>(mMemoryCacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
};
mMemoryCacheSize表示LruCache的容量值,sizeOf则是每个bitmap占用多大。
其次,LruCache使用起来跟HashMap差不多,主要是put()加入缓存、get()获取缓存
// 加入缓存
mMemoryCache.put(key, bitmap);
// 取出缓存,可能为空
Bitmap bitmap = mMemoryCache.get(key)
LruCache源码
看一下重要的几个变量
private final LinkedHashMap<K, V> map; // 存储缓存
/** Size of this cache in units. Not necessarily the number of elements. */
private int size; // 当前缓存的大小
private int maxSize; // 缓存的最大容量
LruCache使用LinkedHashMap来缓存,LinkedHashMap简直就是为了LruCache定制的,如果不熟悉的话可以看下这篇文章《LinkedHashMap原理和源码分析》
LinkedHashMap继承自HashMap,而且内部维护着一个双向队列,可以设置根据访问动作或者插入动作来调整顺序。
我们根据访问动作会来调整顺序,当插入一个结点时候,将该结点插入到队列的尾部,或者,访问某个结点时,会将该结点调整到队列尾部。这样保证当超过缓存容量的时候,直接从头部删除很久没有用过的结点就可以了。
以上基本就是LruCache的基本原理了。
看一个get()、put()方法:
public final V get(K key) {
if (key == null) {
// 不支持key、value为null
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue; // 获取到值,直接返回
}
missCount++;
}
V createdValue = create(key); // 默认是返回null,可以重写表示新建一个默认值
if (createdValue == null) {
return null;
}
// 走到这里,表示create(key) 一个默认值createdValue
// 以下走插入createdValue流程
synchronized (this) {
createCount++;
mapValue = map.put(key, createdValue);
if (mapValue != null) {
// There was a conflict so undo that last put
// 说明插入的key有冲突了,需要撤销默认值,恢复插入原来的值mapValue
map.put(key, mapValue);
} else {
// 计算增加size
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
// entryRemoved默认是空实现,每当移除一个entry都会调用
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
// 核心方法,整理缓存,超过限制会清除缓存
trimToSize(maxSize);
return createdValue;
}
}
public final V put(K key, V value) {
if (key == null || value == null) {
// 不支持key、value为null
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {
putCount++;
size += safeSizeOf(key, value); // 增加新的value的size
previous = map.put(key, value); // 添加<key, value>
if (previous != null) {
size -= safeSizeOf(key, previous); // 减去旧的value的size
}
}
if (previous != null) {
// entryRemoved默认是空实现,每当移除一个entry都会调用
entryRemoved(false, key, previous, value);
}
// 核心方法,整理缓存,超过限制会清除缓存
trimToSize(maxSize);
return previous;
}