Android中的LruCache的原理和使用

LruCache,虽然很多文章都把LRU翻译成“最近最少使用”缓存策略,但Android中的LruCache真的如此吗?

答案是No,它只做到了控制“最近使用”!

原理

数据结构

LruCache采用LinkedHashMap作为存储的数据结构,那么为什么是LinkedHashMap?

LinkedHashMap特性简介

  • LinkedHashMap基于HashMap,具有HashMap高效查找、自动扩容等特性
  • 在HashMap基础上,增加了一个双向链表存储K-V对、实现了自己的遍历器LinkedHashIterator,默认情况下可以做到根据数据插入顺序有序地遍历
  • 提供重载构造方法供外部控制accessOrder,以实现根据访问顺序有序地遍历

初始化

    public LruCache(int maxSize) {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
this.maxSize = maxSize;
this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
}

LruCache的构造方法如上,可见LruCache初始化时就使用了上面提到的LinkedHashMap的第三点特性,即在数据结构层面实现了“最近使用”。

存储

当调用put方法添加/设置存储内容时,LruCache依次做了这么几件事:

  1. 判空,即不允许key/value为null
  2. 总容量size增加上计算传入的K-V大小
  3. 将传入的K-V存入LinkedHashMap
  4. 如过LinkedHashMap中已存在相同K,总容量size减去替换掉的K-VOld大小
  5. 通知VOld被替换(子类实现entryRemoved以监听)
  6. 比较总容量size和最大容量maxSize,若大于maxSize则循环移除LinkedHashMap头结点(即最久未被访问的结点)直至size小于等于maxSize

获取

当调用get方法获取存储内容时,LruCache依次做了这些事:

  1. 判空
  2. 从LinkedHashMap中取出与K对应的V值并返回。如果子类未实现create方法以达到当缓存未命中时创建并存入新V的话,返回null,get流程结束。
  3. 通过create创建VNew,并尝试把VNew存储到LinkedHashMap中,流程类似存储过程,不同之处在于当K冲突时,会舍弃掉新创建的VNew。不要奇怪为什么明明上面通过K取V的时候没取到,这里却会K冲突,因为LruCache为了性能考虑(防止子类自定义的create方法耗时过长影响get方法执行性能),只对从LinkedHashMap中取值的过程做了同步处理,这样在多线程的情况下就可能出现A线程在create的时候,B线程已经将K-VB存入了map。
  4. 返回上面创建的VNew或者VB

使用

用LruCache实现一个简单的图片缓存

    class LruImageCache extends LruCache<String, Bitmap> {
private static final String TAG = "LruImageCache";
private static final int DEFAULT_CACHE_SIZE = 20 * 1024 * 1024; public LruImageCache() {
this(DEFAULT_CACHE_SIZE);
} public LruImageCache(int maxSize) {
super(maxSize);
} @Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
Log.d(TAG, "cache removed: " + key);
} @Override
protected Bitmap create(String key) {
// 从本地、网络获取图片
return loadImageFromIO(key);
} @Override
protected int sizeOf(String key, Bitmap value) {
return value.getAllocationByteCount();
}
}
//使用
Bitmap b = LruImageCache.get("http://image-path");

最新文章

  1. Ubuntu下Android Studio环境搭建
  2. easyui-datagrid自动合并行
  3. 【洛谷P1351】联合权值
  4. 如何保护 .NET 应用的安全?
  5. [转]SVN的trunk branch tag
  6. MyEclipse10搭建Strust2开发环境
  7. java数组排序之冒泡排序
  8. Unix/Linux环境C编程入门教程(33) 命令和鼠标管理用户和组
  9. dedecms====phpcms 区别==[工作]
  10. java 注解的实现机制
  11. 一致性 Hash 算法的实际应用
  12. 蓝屏代码PAGE_FAULT_IN_NONPAGED_AREA的解决方法
  13. 每天一个linux命令:iostat
  14. [译]课程 1: 使用 Quartz
  15. Windows 下单机最大TCP连接数
  16. SqlServer中的数据库分类
  17. 总结一下《vue的使用》
  18. Grunt经常使用插件及演示样例说明
  19. nodelua
  20. HihoCoder - 1794:拼三角形 (状压DP)

热门文章

  1. elasticsearch集群配置 (Tobe Continue)
  2. Buy a Ticket,题解
  3. Azure Web App (一)发布你的Net Core Web 项目
  4. VS2017未能添加对&quot;System.Drawing.dll&quot;的引用
  5. response对象乱码--解决
  6. Jenkins - 解决集成 jmeter+ant 发送邮件时报错:java.lang.ClassNotFoundException: javax.mail.internet.MimeMessage
  7. Scala 基础(三):Scala语言快速开发入门
  8. The Modules of Event-driven
  9. 微信小程序动态修改title,动态配置title,动态配置头部,微信小程序动态配置头部
  10. bzoj3791作业*