一、原理

LruCache 其实挺简单的,本质是对LinkHashMap的封装,然后通过设置maxSize来控制LinkHashMap的容量。

二、注意点

2.1 LruCache 是线程安全的

它的所有属性都是私有属性

image-20200907092730822

对私有属性的settergetter操作都是加了锁处理

image-20200907092920801 image-20200907094458203

2.2 key/value不能为null

和HashMapbuts,LruCache put时不允许key和vale都不能为空

image-20200907093211744

2.3 maxSize 不一定生效

LruCache是通过sizeOf()计算value的大小的,默认情况下,只会返回1,也就是LinkHashMap的容量加一。

image-20200907093603127

如果用LruCache缓存Bitmap等对象,那么LruCache可能永远也不会释放,因为对于缓存Bitamp来说,一般情况下,ma xsize都会设置为10m,这样的话,map的容量要到10m的条目数才会释放一个Bitmap

解决方案是,创建LruCache时重写sizeOf方法:

int cacheSize = 4 * 1024 * 1024; // 4MiB
LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
// 重写 `sizeOf`方法
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
}

2.4 返回默认的返回值

由于LruCache是对LinkHashMap的封装,因此,当key对应的value不存在时,会返回null,如果你需要不返回null,可以通过覆盖create()方法创建默认的返回值。

int cacheSize = 20;
LruCache<String, String> strCache = new LruCache<String, String>(cacheSize) {
// 重写 `create`方法
protected String create(String key) {
return "默认值";
}
}

2.5 在对象被移除之前操作对象

如果你希望在对象被回收之前做一些额外的超过,比如:移除Bitmap时,主动释放Bitmap,那么可以重写entryRemoved方法。

int cacheSize = 4 * 1024 * 1024; // 4MiB
LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
// 重写 `sizeOf`方法
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}

/**
* @param evicted 只有当容量超过maxsize,自动释放条目时为true,put\get\remove时为false
* @param newValue 如果是主动释放时或remove时,该值为null;如果是put,该值为put的值;如果是get时,并且
* key对应的value不存在时,并且`create`不为空,old 和 new 都为`create`创建的默认值
*/
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue){
oldValue.recycle();
}
}