Android图片缓存工具类LruCache原理和使用介绍

LruCache & DiskLruCache原理

常用的三级缓存主要有LruCache、DiskLruCache、网络,其中LruCache对应内存缓存、

DiskLruCache对应持久化缓存。Lru表示最近最少使用,意思是当缓存到达限制时候,优先淘汰近

期内最少使用的缓存,LruCache和DisLruCache都是如此。

比如说Android中常来缓存Bitmap,我们先依次从LruCache、DiskLruCache获取,最后才网络下

载。

本篇主要从原理和源码分析LruCache和DiskLruCache

LruCache

LruCache<K, V> 可以在内存中缓存数据,内部使用最近最少使用算法,优先淘汰最近时间内最少
次使用的缓存对象。

LruCache使用
java 复制代码
LruCache<String, Bitmap> mMemoryCache;
mMemoryCache = new LruCache<String, Bitmap>(mMemoryCacheSize)
{ @Override
protected int sizeOf(String key, Bitmap value)
{ return value.getByteCount();
}
};
1234567

mMemoryCacheSize表示LruCache的容量值,sizeOf则是每个bitmap占用多大。

其次,LruCache使用起来跟HashMap差不多,主要是put()加入缓存、get()获取缓存

java 复制代码
// 加入缓存
mMemoryCache.put(key, bitmap);
// 取出缓存,可能为空
Bitmap bitmap = mMemoryCache.get(key)
1234
LruCache源码

看一下重要的几个变量

java 复制代码
private final LinkedHashMap<K, V> map; // 存储缓存
/** Size of this cache in units. Not necessarily the number of elements. */
private int size; // 当前缓存的大小
private int maxSize; // 缓存的最大容量
1234

LruCache使用LinkedHashMap来缓存,LinkedHashMap简直就是为了LruCache定制的,如果不熟

悉的话可以看下这篇文章《LinkedHashMap原理和源码分析》

LinkedHashMap继承自HashMap,而且内部维护着一个双向队列,可以设置根据访问动作或者插

入动作来调整顺序。

我们根据访问动作会来调整顺序,当插入一个结点时候,将该结点插入到队列的尾部,或者,访

问某个结点时,会将该结点调整到队列尾部。这样保证当超过缓存容量的时候,直接从头部删除

很久没有用过的结点就可以了。

以上基本就是LruCache的基本原理了。

看一个get()、put()方法:
java 复制代码
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;
}
}
123456789101112131415161718192021222324252627282930313233343536373839404142
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;
}
123456789101112131415161718192021222324

trimToSize() 在增加缓存之后会调用,负责整理缓存,超过限制会清除旧的缓存

java 复制代码
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 || map.isEmpty())
{ break;
}
// LinkHashMap.entrySet()是LinkedEntrySet,是有序的
Map.Entry<K, V> toEvict =
map.entrySet().iterator().next();
// 移除队头元素,最近最少使用的节点
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
1234567891011121314151617181920212223242526

trimToSize()利用了LinkedHashMap的特性,当超过限制时候,移除头部的结点,因为头部结点是

最旧的结点。

LruCache不支持key为null,而HashMap支持key、value为null,而HashTable、

ConcurrentHashMap都不支持key 或value为null。

DiskLruCache

DiskLruCache整体的思想跟LruCache是一样的,不过它操作的是本地磁盘的文件实体,而且使用
起来也麻烦了很多。
DiskLruCache的使用
DiskLruCache并不是Android内置的库,而且需要存储权限

java 复制代码
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

这里有DiskLruCache介绍地址:https://github.com/JakeWharton/DiskLruCache

相关推荐
苏坡余3 分钟前
Android Pixel7 13.0源码编译记录
android
Lanren的编程日记10 分钟前
Flutter 鸿蒙应用内存管理优化实战:对象池+智能缓存+泄漏检测,全方位提升应用稳定性
flutter·缓存·华为·harmonyos
灵魂学者14 分钟前
使用 Android Studio 进行 HbuilderX H5+App 离线打包
android·ide·android studio·hbuilderx·apk build
scan72416 分钟前
将记忆存储到数据库中
android
黄林晴34 分钟前
Kotlin 2.4.0-Beta2 发布,语法与多平台能力全线革新
android·kotlin
恋猫de小郭34 分钟前
Bun 官方将正式支持 Android,Claude Code 未来可以直接在手机上跑
android·前端·ai编程
nLYA SCOL1 小时前
MySQL数据的增删改查(一)
android·javascript·mysql
Kapaseker1 小时前
高阶函数到底高阶在哪里?
android·kotlin
且随疾风前行.1 小时前
Android 12 (AOSP) 添加自定义系统服务
android
耳边轻语9991 小时前
Hermes 如何省token-配置
人工智能·缓存