图片缓存/内存缓存/LruCache

三级缓存

内存缓存

我们的缓存容量是有限的,它会面临一个问题:当有新的内容需要加入我们的缓存,但我们的缓存空闲的空间不足以放进新的内容时,如何舍弃原有的部分内容从而腾出空间用来放新的内容?

解决这个问题的算法有多种,比如LRU,LFU,FIFO等

  • 官方推荐使用LRU并且Google在SDK中为我们提供对LRU算法的实现类android.util.LruCache。
  • 需要注意区分的是LRU和LFU。
    • 前者是最近最少使用,即淘汰最长时间未使用的对象;以时间为参考。
    • 后者是最不频繁使用,即淘汰一段时间内使用最少的对象。以使用过次数为参考。
    • 例子:比如我们缓存对象的顺序是:A B C B D A C A,当需要淘汰一个对象时
      • 如果采用LRU算法,则淘汰的是B,因为它是最长时间未被使用的
      • 如果采用LFU算法,则淘汰的是D,因为在这段时间内它只被使用了一次,是最不经常使用的。
  • 图片的内存缓存基于LruCache类,类LruCache实现LRU算法缓存置换策略,LRU算法基于LinkedHashMap类,LinkedHashMap基于数据结构之双向循环链表。

小结:
不论图片的内存缓存算法是哪一种,这些算法解决的是超出最大值时如何自动回收的问题。

LinkedHashMap

是什么?

LinkedHashMap继承自HashMap,不同的是,它是一个双向循环链表,它的每一个数据结点都有两个指针,分别指向直接前驱和直接后继。

成员变量accessOrder
  • accessOrder是指定它的排序方式,当它为false时,只按插入的顺序排序,即新放入的元素会在链表的尾部;
  • 而当它为true时,更新或访问某个节点的数据时,这个对应的结点也会被放到尾部。

问题

LruCache怎么知道添加完新元素后是否超过总缓存?

添加新元素后,先调用sizeOf()计算元素大小,在与当前缓存大小相加得到新的缓存大小,最后调用trimMemory()检查并修剪内存。

当添加新元素会超过总缓存,那么怎么基于最近最少使用算法移除元素?

while循环,通过不断调用LinkedHashMap.eldest()获得头节点指向下一个节点(最老节点),然后LinkedHashMap.remove()将其移出,在计算缓存大小,直到缓存大小小于总大小,循环结束。

Android源码解析——LruCache


MyBitmapUtils.display(ImageView ivPic, String url)

  • 提供给外部进行图片显示和图片缓存的接口
  • 封装了对图片进行三级缓存逻辑

NetCacheUtils. getBitmapFromNet(ImageView ivPic, String url)

  • 提供给外部从网络获取Bitmap的接口
  • 封装了从网络获取图片并缓存本地和内存的细节

LocalCacheUtils

MemoryCacheUtils

  • Android 虚拟机默认分配给每个App 固定大小的内存空间。
  • 图片大小 = 图片的总像素 * 每个像素占用的大小
    例如一张1920x1080的JPG图片,在Android 系统中是以ARGB格式解析的,即一个像素需占用4个字节,图片的大小=1920x1080x4=7M。

Android中图片的三级缓存

你可能感兴趣的:(图片缓存/内存缓存/LruCache)