原文地址:https://hexige.github.io/blog/2017/07/24/LruCache/
谷歌官方建议使用LruCache(least recentlly use 最近最少使用算法)来保存Bitmap对象;
使用
private static int MAX_SIZE = (int)(Runtime.getRuntime().maxMemory()/8);
LruCache<String,BItmap> mBitmapCache = new LruCache<>(MAX_SIZE);
源码
LruCache在内部维护了一个LinkedHashMap,也就是使用了LinkedHashMap的Lru调度算法。
在构造方法中:
- 初始化了cache的大小;
- 初始化LinkedHashMap,accessOrder为true,即为Lru调度方式;
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);
}
get方法
:通过key获取相应的value,或者返回创建新的value。
同时此记录会移至队列的尾部;
public final V get(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
/*
* Attempt to create a value. This may take a long time, and the map
* may be different when create() returns. If a conflicting value was
* added to the map while create() was working, we leave that value in
* the map and release the created value.
*/
//create()方法默认为空实现,如需在未获得value时创建新的对象,则可重写此方法;
V createdValue = create(key);
if (createdValue == null) {
return null;
}
//如果新创建了对象
synchronized (this) {
createCount++;
//将createdValue放入map中,同时将原来key对应的value保存到mapValue中
mapValue = map.put(key, createdValue);
if (mapValue != null) {
// There was a conflict so undo that last put
//mapValue不为空则撤销上一步操作
map.put(key, mapValue);
} else {
//加入新的对象后,重新计算size
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
//每次加入新对象,都会调用trimToSize方法查看时候需要回收
trimToSize(maxSize);
return createdValue;
}
}
trimToSize():
根据maxSize来调整cache的大小
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!");
}
//如果当前size小于maxSize,break
if (size <= maxSize) {
break;
}
//如果当前链表头部元素为null,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);
//回收次数+1
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}