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

打印 上一主题 下一主题

主题 1747|帖子 1747|积分 5241

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
LruCache & DiskLruCache原理


常用的三级缓存重要有LruCache、DiskLruCache、网络,此中LruCache对应内存缓存、
DiskLruCache对应长期化缓存。Lru表示最近最少使用,意思是当缓存到达限制时候,优先淘汰近
期内最少使用的缓存,LruCache和DisLruCache都是如此。
好比说Android中常来缓存Bitmap,我们先依次从LruCache、DiskLruCache获取,最后才网络下
载。
本篇重要从原理和源码分析LruCache和DiskLruCache

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



LruCache使用


  1. LruCache<String, Bitmap> mMemoryCache;
  2. mMemoryCache = new LruCache<String, Bitmap>(mMemoryCacheSize)
  3. { @Override
  4. protected int sizeOf(String key, Bitmap value)
  5. { return value.getByteCount();
  6. }
  7. };
  8. 1234567
复制代码
mMemoryCacheSize表示LruCache的容量值,sizeOf则是每个bitmap占用多大。
其次,LruCache使用起来跟HashMap差不多,重要是put()加入缓存、get()获取缓存
  1. // 加入缓存
  2. mMemoryCache.put(key, bitmap);
  3. // 取出缓存,可能为空
  4. Bitmap bitmap = mMemoryCache.get(key)
  5. 1234
复制代码
LruCache源码
看一下重要的几个变量


  1. private final LinkedHashMap<K, V> map; // 存储缓存
  2. /** Size of this cache in units. Not necessarily the number of elements. */
  3. private int size; // 当前缓存的大小
  4. private int maxSize; // 缓存的最大容量
  5. 1234
复制代码
LruCache使用LinkedHashMap来缓存,LinkedHashMap简直就是为了LruCache定制的,如果不熟
悉的话可以看下这篇文章《LinkedHashMap原理和源码分析》


LinkedHashMap继承自HashMap,而且内部维护着一个双向队列,可以设置根据访问动作大概插
入动作来调解顺序。

我们根据访问动作会来调解顺序,当插入一个结点时候,将该结点插入到队列的尾部,大概,访
问某个结点时,会将该结点调解到队列尾部。如许包管当凌驾缓存容量的时候,直接从头部删除
很久没有效过的结点就可以了。
以上基本就是LruCache的基本原理了。

看一个get()、put()方法:


  1. public final V get(K key) {
  2. if (key == null) { // 不支持key、value为null
  3. throw new NullPointerException("key == null");
  4. }
  5. V mapValue;
  6. synchronized (this) {
  7. mapValue = map.get(key);
  8. if (mapValue != null) {
  9. hitCount++;
  10. return mapValue; // 获取到值,直接返回
  11. }
  12. missCount++;
  13. }
  14. V createdValue = create(key); // 默认是返回null,可以重写表示新建一个默认值
  15. if (createdValue == null)
  16. { return null;
  17. }
  18. // 走到这里,表示create(key) 一个默认值createdValue
  19. // 以下走插入createdValue流程
  20. synchronized (this)
  21. { createCount++;
  22. mapValue = map.put(key, createdValue);
  23. if (mapValue != null) {
  24. // There was a conflict so undo that last put
  25. // 说明插入的key有冲突了,需要撤销默认值,恢复插入原来的值mapValue
  26. map.put(key, mapValue);
  27. } else {
  28. // 计算增加size
  29. size += safeSizeOf(key, createdValue);
  30. }
  31. }
  32. if (mapValue != null) {
  33. // entryRemoved默认是空实现,每当移除一个entry都会调用
  34. entryRemoved(false, key, createdValue, mapValue);
  35. return mapValue;
  36. } else {
  37. // 核心方法,整理缓存,超过限制会清除缓存
  38. trimToSize(maxSize);
  39. return createdValue;
  40. }
  41. }
  42. 123456789101112131415161718192021222324252627282930313233343536373839404142
  43. public final V put(K key, V value) {
  44. if (key == null || value == null) { // 不支持key、value为null
  45. throw new NullPointerException("key == null || value == null");
  46. }
  47. V previous;
  48. synchronized (this) {
  49. putCount++;
  50. size += safeSizeOf(key, value); // 增加新的value的size
  51. previous = map.put(key, value); // 添加<key, value>
  52. if (previous != null) {
  53. size -= safeSizeOf(key, previous); // 减去旧的value的size
  54. }
  55. }
  56. if (previous != null) {
  57. // entryRemoved默认是空实现,每当移除一个entry都会调用
  58. entryRemoved(false, key, previous, value);
  59. }
  60. // 核心方法,整理缓存,超过限制会清除缓存
  61. trimToSize(maxSize);
  62. return previous;
  63. }
  64. 123456789101112131415161718192021222324
复制代码
trimToSize() 在增长缓存之后会调用,负责整理缓存,凌驾限制会清除旧的缓存
  1. public void trimToSize(int maxSize)
  2. { while (true) {
  3. K key;
  4. V value;
  5. synchronized (this) {
  6. if (size < 0 || (map.isEmpty() && size != 0)) {
  7. throw new IllegalStateException(getClass().getName()
  8. + ".sizeOf() is reporting inconsistent results!");
  9. }
  10. if (size <= maxSize || map.isEmpty())
  11. { break;
  12. }
  13. // LinkHashMap.entrySet()是LinkedEntrySet,是有序的
  14. Map.Entry<K, V> toEvict =
  15. map.entrySet().iterator().next();
  16. // 移除队头元素,最近最少使用的节点
  17. key = toEvict.getKey();
  18. value = toEvict.getValue();
  19. map.remove(key);
  20. size -= safeSizeOf(key, value);
  21. evictionCount++;
  22. }
  23. entryRemoved(true, key, value, null);
  24. }
  25. }
  26. 1234567891011121314151617181920212223242526
复制代码
trimToSize()利用了LinkedHashMap的特性,当凌驾限制时候,移除头部的结点,因为头部结点是
最旧的结点。
LruCache不支持key为null,而HashMap支持key、value为null,而HashTable、
ConcurrentHashMap都不支持key 或value为null。

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


  1. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
复制代码
这里有DiskLruCache介绍地址:https://github.com/JakeWharton/DiskLruCache


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

郭卫东

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表