LRU缓存策略
LRU((Least Recently Used)是最近最少使用的算法,它的核心思想是当缓存满时,会优先淘汰那些最近最少使用的缓存对象。采用LRU算法的缓存有两种:LrhCache和DiskLruCache
LruCache是Android 3.1所提供的一个缓存类,所以在Android中可以直接使用LruCache实现内存缓存。而DiskLruCache目前在Android 还不是Android SDK的一部分,但Android官方文档推荐使用该算法来实现硬盘缓存。
api介绍
LruCache是一个泛型类,需要指定相应的k和v
构造方法
public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}
使用LinkedHashMap来存放缓存列表,LinkedHashMap是双向链表结构,里面的数据是有序,可以是插入的顺序或者访问的顺序
put
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
...
synchronized (this) {
putCount++;
size += safeSizeOf(key, value);
previous = map.put(key, value);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
...
}
- key和value都不能为空
- 通过使用synchronized来实现线程安全
- sizeof返回每个缓存的大小
size
protected int sizeOf(K key, V value) {
return 1;
}
使用的时候需要重载这个方法来指明每个缓存的大小
trimToSize-控制大小
public 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 = map.eldest();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
每次调用put方法之后会调用这个方法控制缓存的大小,如果超过了maxSize,会移除掉最后一个
使用
创建一个4M的存放bitmap的缓存
val cacheSize = 4*1024*1024 //4MiB
val bitmapCache = object: LruCache<String, Bitmap>(cacheSize){
override fun sizeOf(key: String, value: Bitmap): Int {
return value.byteCount
}
override fun entryRemoved(evicted: Boolean, key: String?, oldValue: Bitmap?, newValue: Bitmap?) {
super.entryRemoved(evicted, key, oldValue, newValue)
Log.d("tag", "remove:"+key)
}
}
创建bitmap,添加到相应的缓存中
//使用Config.RGB_565,一个像素占两个字节,总共500,000个字节
val bitmap = Bitmap.createBitmap(500, 500, Bitmap.Config.RGB_565)
for (item in (0..9)){
Log.d("tag", "index:"+item)
bitmapCache.put(item.toString(), bitmap)
}
打印
D/tag: index:0
D/tag: index:1
D/tag: index:2
D/tag: index:3
D/tag: index:4
D/tag: index:5
D/tag: index:6
D/tag: index:7
D/tag: index:8
D/tag: remove:0
D/tag: index:9
D/tag: remove:1
添加第9的时候,已经超过缓存,会移除掉最后一个,然后会在entryRemoved方法回调