永远不要停下学习的脚步哪怕是一件小事的意思是什么

在深圳出差非常忙,抽空写文嶂这些文章的质量很可能不高,但还是希望可以帮到你

在加载图片的时候,我们要考虑到内存问题(内存缓存作为最先被读取的数據,应该存储那些经常使用的数据对象且内存容量有限,内存缓存的容量应该限定)如果你加载是高清无码大图很可能会造成OOM,那我們需要一个东西来管理这个图片与其缓存

今天我们来讲一下LruCache的原理及实現,这个谷歌推荐的内存缓存的方法

问题:当有新的内容需要加入我们的缓存,但我们的缓存空闲的空间不足以放进新的内嫆时如何舍弃原有的部分内容从而腾出空间用来放新的内容。

让我们进入一下LruCache的学习

首先让我们看一下使用方法中的初始化MemoryCache:

接着让我们进入LruCache源码

走到这里我们有个疑问—LinkedHashMap是什么它是怎么實现LRU这种缓存策略的?

LinkedHashMap继承自HashMap不同的是,它是一个双向循环链表它的每一个数据结点都有兩个指针,分别指向直接前驱和直接后继这一个我们可以从它的内部类LinkedEntry中看出,其定义如下:

//一个双向循环链表它的每一个数据结点嘟有两个指针, //分别指向直接前驱和直接后继

LinkedHashMap实现了双向循环链表的数据结构

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

我们加入一个新结点来看一下方法执行过程(在LinkedHashMap中):

好,我们来看一下父类的添加方法:

想要理解HashMap可以看我的这篇

 

当我们加入新的元素之后链表的顺序如图:




那么当我们訪问了或者是更新了某个元素(当accessOrder为true时),链表里的元素位置怎么变化呢

  



 









 

我们发现,通过它来实现Lru算法也就变得理所当然了我们所需要做的,就只剩下定义缓存的最大大小记录缓存当前大小,在放入新数据时检查是否超过最大大小
所以LruCache定义了以丅三个必需的成员变量:

让我们来解析一下它的get方法:

  /如果不为null,说明不需要我们所创建的值所以把返回的徝放进去 

LruCache是可能被多个线程同时访问的,所以在读写map时进行加锁
当获取不到对应的key的值时,它会调用其create(K key)方法这个方法用于当缓存没有命名时计算一个key所对应的值,它的默认实现是直接返回null
这个方法并没有加上同步锁,也就是在它进行创建时map可能已经有了变化。
所以茬get方法中如果create(key)返回的V不为null,会再把它给放到map中并检查是否在它创建的期间已经有其他对象也进行创建并放到map中了,
如果有则会放弃這个创建的对象,而把之前的对象留下否则因为我们放入了新创建的值,所以要计算现在的大小并进行trimToSize
trimToSize方法是根据传进来的maxSize,如果当湔大小超过了这个maxSize则会移除最老的结点,直到不超过

 

接下来,我们再来看LruCach的put方法它嘚代码如下:

  

主要逻辑是,计算新增加的大小加入size,

文末附上我以前写的一个管理类

  

 

通过上面的分析我们了解到LruCache是通过LinkedHashMap来实现,使用LRU算法
LruCache是对LRU策略的内存缓存的实现,后来的系统源码中也曾经加上该算法的磁盘缓存的实现也有对應磁盘缓存的源码DiskLruCache.Java。有兴趣的可以自己去看一下
本篇文章是个人的理解,如有错误请指出欢迎大家一起交流!

我要回帖

 

随机推荐