阿里云的国际网站建设,一起做网店网站,企业网站建设方案机构,厦门黄页LruCache DiskLruCache原理。 常用的三级缓存主要有LruCache、DiskLruCache、网络#xff0c;其中LruCache对应内存缓存、 DiskLruCache对应持久化缓存。Lru表示最近最少使用#xff0c;意思是当缓存到达限制时候#xff0c;优先淘汰近 期内最少使用的缓存#xff0c…LruCache DiskLruCache原理。 常用的三级缓存主要有LruCache、DiskLruCache、网络其中LruCache对应内存缓存、 DiskLruCache对应持久化缓存。Lru表示最近最少使用意思是当缓存到达限制时候优先淘汰近 期内最少使用的缓存LruCache和DisLruCache都是如此。 比如说Android中常来缓存Bitmap我们先依次从LruCache、DiskLruCache获取最后才网络下 载。 本篇主要从原理和源码分析LruCache和DiskLruCache LruCacheLruCacheK, V 可以在内存中缓存数据内部使用最近最少使用算法优先淘汰最近时间内最少 次使用的缓存对象。
LruCache使用
LruCacheString, Bitmap mMemoryCache;
mMemoryCache new LruCacheString, Bitmap(mMemoryCacheSize)
{ Override
protected int sizeOf(String key, Bitmap value)
{ return value.getByteCount();
}
};
1234567
mMemoryCacheSize表示LruCache的容量值sizeOf则是每个bitmap占用多大。 其次LruCache使用起来跟HashMap差不多主要是put()加入缓存、get()获取缓存
// 加入缓存
mMemoryCache.put(key, bitmap);
// 取出缓存可能为空
Bitmap bitmap mMemoryCache.get(key)
1234
LruCache源码 看一下重要的几个变量
private final LinkedHashMapK, 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()方法
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() 在增加缓存之后会调用负责整理缓存超过限制会清除旧的缓存
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.EntryK, 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内置的库而且需要存储权限
uses-permission android:nameandroid.permission.READ_EXTERNAL_STORAGE /
uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE /
这里有DiskLruCache介绍地址https://github.com/JakeWharton/DiskLruCache