马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
LruCache & DiskLruCache原理。
常用的三级缓存重要有LruCache、DiskLruCache、网络,此中LruCache对应内存缓存、
DiskLruCache对应长期化缓存。Lru表示最近最少使用,意思是当缓存到达限制时候,优先淘汰近
期内最少使用的缓存,LruCache和DisLruCache都是如此。
好比说Android中常来缓存Bitmap,我们先依次从LruCache、DiskLruCache获取,最后才网络下
载。
本篇重要从原理和源码分析LruCache和DiskLruCache
LruCache
LruCache<K, V> 可以在内存中缓存数据,内部使用最近最少使用算法,优先淘汰最近时间内最少
次使用的缓存对象。
LruCache使用
- 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()获取缓存
- // 加入缓存
- mMemoryCache.put(key, bitmap);
- // 取出缓存,可能为空
- Bitmap bitmap = mMemoryCache.get(key)
- 1234
复制代码 LruCache源码
看一下重要的几个变量
- 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()方法:
- 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.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内置的库,而且需要存储权限
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
复制代码 这里有DiskLruCache介绍地址:https://github.com/JakeWharton/DiskLruCache
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |