Android中的LruCache的原理和使用
2024-09-04 02:33:34
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依次做了这么几件事:
- 判空,即不允许key/value为null
- 总容量size增加上计算传入的K-V大小
- 将传入的K-V存入LinkedHashMap
- 如过LinkedHashMap中已存在相同K,总容量size减去替换掉的K-VOld大小
- 通知VOld被替换(子类实现entryRemoved以监听)
- 比较总容量size和最大容量maxSize,若大于maxSize则循环移除LinkedHashMap头结点(即最久未被访问的结点)直至size小于等于maxSize
获取
当调用get方法获取存储内容时,LruCache依次做了这些事:
- 判空
- 从LinkedHashMap中取出与K对应的V值并返回。如果子类未实现create方法以达到当缓存未命中时创建并存入新V的话,返回null,get流程结束。
- 通过create创建VNew,并尝试把VNew存储到LinkedHashMap中,流程类似存储过程,不同之处在于当K冲突时,会舍弃掉新创建的VNew。不要奇怪为什么明明上面通过K取V的时候没取到,这里却会K冲突,因为LruCache为了性能考虑(防止子类自定义的create方法耗时过长影响get方法执行性能),只对从LinkedHashMap中取值的过程做了同步处理,这样在多线程的情况下就可能出现A线程在create的时候,B线程已经将K-VB存入了map。
- 返回上面创建的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");
最新文章
- Ubuntu下Android Studio环境搭建
- easyui-datagrid自动合并行
- 【洛谷P1351】联合权值
- 如何保护 .NET 应用的安全?
- [转]SVN的trunk branch tag
- MyEclipse10搭建Strust2开发环境
- java数组排序之冒泡排序
- Unix/Linux环境C编程入门教程(33) 命令和鼠标管理用户和组
- dedecms====phpcms 区别==[工作]
- java 注解的实现机制
- 一致性 Hash 算法的实际应用
- 蓝屏代码PAGE_FAULT_IN_NONPAGED_AREA的解决方法
- 每天一个linux命令:iostat
- [译]课程 1: 使用 Quartz
- Windows 下单机最大TCP连接数
- SqlServer中的数据库分类
- 总结一下《vue的使用》
- Grunt经常使用插件及演示样例说明
- nodelua
- HihoCoder - 1794:拼三角形 (状压DP)
热门文章
- elasticsearch集群配置 (Tobe Continue)
- Buy a Ticket,题解
- Azure Web App (一)发布你的Net Core Web 项目
- VS2017未能添加对";System.Drawing.dll";的引用
- response对象乱码--解决
- Jenkins - 解决集成 jmeter+ant 发送邮件时报错:java.lang.ClassNotFoundException: javax.mail.internet.MimeMessage
- Scala 基础(三):Scala语言快速开发入门
- The Modules of Event-driven
- 微信小程序动态修改title,动态配置title,动态配置头部,微信小程序动态配置头部
- bzoj3791作业*