-
概述
LruCache是一个泛型类,它内部采用一个LinkedHashMap以强引用的方式储存外界的缓存对象,为其提供了get和put方法来完成缓存的获取和添加操作。 当缓存存满时,LruCache会移除较早使用的缓存对象, 然后再添加新的缓存对象。 -
构造方法
/** Size of this cache in units. Not necessarily the number of elements. */
private int size; //当前缓存大小
private int maxSize; //最大缓存大小
private int putCount; //put的次数(为LruCache添加缓存对象的次数)
private int createCount; // create的次数
private int evictionCount; //回收的次数
private int hitCount; //命中缓存次数
private int missCount; // 未命中次数
/**
* @param maxSize for caches that do not override {@link #sizeOf}, this is
* the maximum number of entries in the cache. For all other caches,
* this is the maximum sum of the sizes of the entries in this cache.
*/
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);
}
例子
int maxMemory = (int) (Runtime.getRuntime().maxMemory())/1024;//获取可用内存,转换为单位KB
int maxCache = maxMemory/10;//缓存大小为可用内存的1/10
LruCache mMemoryCache = new LruCache<String,Bitmap>(maxCache){
@Override//重写sizeOf方法,返回每条数据占用的内存
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight() / 1024;
//return value.getByteCount() / 1024;
}
};
这里sizeOf和 maxMemory要统一单位, 用于计算对象大小。
2. get()
public final V get(K key) {
if (key == null) {//如果key为null,抛出异常
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
mapValue = map.get(key); // 读取key对应的value
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.
*/
//尝试创建value,可能会消耗一定的时间,当创建完成时,map可能已经发生变化如果此时发现创建时使用的key已经存在,导致冲突,丢弃掉create创建的值
如果未获取到value,调用create方法,尝试创建对象
//也可以重写此方法。决定获取不到的时候该添加什么。
V createdValue = create(key);
if (createdValue == null) {
return null;
}
//以下部分为创建之后对map的修改动作,包括存放对象,调整size等。
synchronized (this) {
createCount++;
mapValue = map.put(key, createdValue);
if (mapValue != null) {
// There was a conflict so undo that last put
map.put(key, mapValue);
} else {
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
trimToSize(maxSize);
return createdValue;
}
}
3. put
/**
* Caches {@code value} for {@code key}. The value is moved to the head of
* the queue.
*
* @return the previous value mapped by {@code key}.
* 将keyvalue移到队列头部
*/
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
//不允许空key或者空value
}
V previous;
synchronized (this) {
putCount++;
size += safeSizeOf(key, value); //size加上占用的空间
previous = map.put(key, value);//linkedHashMap.put操作
if (previous != null) {
//如果之前的key已经有对应的值了 减少size
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
//并且移除
entryRemoved(false, key, previous, value);//空方法 可以进行一些资源回收的操作。
}
trimToSize(maxSize);
return previous;
}
//size必须大于1;
private int safeSizeOf(K key, V value) {
int result = sizeOf(key, value);
if (result < 0) {
throw new IllegalStateException("Negative size: " + key + "=" + value);
}
return result;
}
/**
* Returns the size of the entry for {@code key} and {@code value} in
* user-defined units. The default implementation returns 1 so that size
* is the number of entries and max size is the maximum number of entries.
*
* <p>An entry's size must not change while it is in the cache.
*/
//用户自定义
protected int sizeOf(K key, V value) {
return 1;
}
4. trimToSize
/**
* Remove the eldest entries until the total of remaining entries is at or
* below the requested size.
*
* @param maxSize the maximum size of the cache before returning. May be -1
* to evict even 0-sized elements.
*/
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);
}
}
在缓存将要满之前,删除最近最少访问的对象,即移除掉map的表头元素
5.remove
public final V remove(K key) {
if (key == null) { //不允许空键
throw new NullPointerException("key == null");
}
V previous;
synchronized (this) {
previous = map.remove(key);
if (previous != null) { //如果存在key,则返回value,更新size;否则没有找到匹配的key,则返回null
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, null); //空方法
}
return previous;
}