图片缓存/内存缓存/LruCache
2017-01-13 本文已影响216人
官先生Y
三级缓存
内存缓存
我们的缓存容量是有限的,它会面临一个问题:当有新的内容需要加入我们的缓存,但我们的缓存空闲的空间不足以放进新的内容时,如何舍弃原有的部分内容从而腾出空间用来放新的内容?
解决这个问题的算法有多种,比如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()将其移出,在计算缓存大小,直到缓存大小小于总大小,循环结束。
MyBitmapUtils.display(ImageView ivPic, String url)
- 提供给外部进行图片显示和图片缓存的接口
- 封装了对图片进行三级缓存逻辑
NetCacheUtils. getBitmapFromNet(ImageView ivPic, String url)
- 提供给外部从网络获取Bitmap的接口
- 封装了从网络获取图片并缓存本地和内存的细节
LocalCacheUtils
MemoryCacheUtils
- Android 虚拟机默认分配给每个App 固定大小的内存空间。
- 图片大小 = 图片的总像素 * 每个像素占用的大小
例如一张1920x1080的JPG图片,在Android 系统中是以ARGB格式解析的,即一个像素需占用4个字节,图片的大小=1920x1080x4=7M。