当前位置: 首页 > news >正文

LruCache和DiskLruCache

前言

Android中的三级缓存主要就是内存缓存和硬盘缓存。

Lru(least recently used)意为最近最少使用算法,核心思想就是当缓存满时,会优先淘汰最近最少使用的缓存对象。

LruCache的使用

在Android中可以直接使用LruCache,算法原理是:把最近使用的对象存储在LinkedHashMap中,当缓存满时,把最近最少使用的对象从内存中移除,并提供了get和put方法类完成缓存的获取和添加操作。

int maxMemory = (int) (Runtime.getRuntime().totalMemory() / 1024);
// 缓存的大小,一般为当前进程可用容量的1/8
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {// 重写sizeOf方法, 计算出要缓存的每张图片的大小@Overrideprotected int sizeOf(String key, Bitmap value) {return value.getRowBytes() * value.getHeight() / 1024;}
};

利用LinkedHashMap的一个特性(accessOrder = true基于访问顺序)再加上对LinkedHashMap的数据操作上锁实现的缓存策略

  • 首先设置内部的LinkedHashMap构造参数accessOrder = true,实现了数据排序按照访问顺序
  • LruCache在调用get()方法是时,会调用LinkedHashMap的get()方法,会将此数据移到队尾
  • 最新访问的数据在尾部,如果要在存入数据,将移除队首最近最少访问的数据

再次总结一下原理:

  • LruCache中维护了一个LinkedHashMap,该LinkedHashMap是以访问顺序排序的
  • 当调用put()方法时,在结合处添加元素,并调用trimToSize()判断缓存是否已满,如果满了删除LinkedHashMap队首的元素
  • 当调用get()方法访问缓存对象时,就会调用LinkedHashMap的get()方法获得对应集合元素,同时会更新该元素到队尾

具体分析不说了,贴一个我觉得写的好的链接:浅析LRUCache原理(Android)

DiskLruCache

// DiskLruCache是不能new出来的, 需要调用open()方法// 缓存地址, app版本号, 一个Key可对应多少个文件, 最多可以缓存多少数据
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)// SD卡存在
getExternalCahceDir()来获取到的是/sdcard/Android/data/<application package>/cache
// SD卡不存在
getCacheDir()获取到的是/data/data/<application package>/cache// 标准open()写法
DiskLruCache mDiskLruCache = null;
try {File cacheDir = getDiskCacheDir(context, "bitmap);if (!cacheDir.exists()) {cacheDir.mkdirs();}mDiskLruCache = DiskLruCache.open(cacheDir, getApplication(context), 1, 10 * 1024 * 1024);
} catch (IOException e) {e.printStackTrace();
}// 子线程中写入操作, 通过DiskLruCache.Editor
try {String imageUrl = "https://imgmy.csdn.net/uploads/201309/01/1378037235_7476.jpg";String key = hashKeyForDisk(imageUrl);DiskLruCache.Editor editor = mDiskLruCache.edit(key);if (editor != null) {OutputStream outputStream = editor.newOutputStream(0);if (downloadUrlToStream(imageUrl, outputStream)) {editor.commit();} else {editor.abort();}}mDiskLruCache.flush();
} catch (IOException e) {e.printStackTrace();
}// 读取操作, 通过DiskLruCAche.Snapshot
try {String imageUrl = "https://img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg";String key = hashKeyForDisk(imageUrl);DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);if (snapShot != null) {InputStream is = snapShot.getInputStream(0);Bitmap bitmap = BitmapFactory.decodeStream(is);mImage.setImageBitmap(bitmap);}
} catch (IOException e) {e.printStackTrace();
}// 移除操作, 一般需要从网络重新获取最新数据的时候才应该调用
try {String imageUrl = "https://img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg";  String key = hashKeyForDisk(imageUrl);  mDiskLruCache.remove(key);
} catch (IOException e) {e.printStackTrace();
}// 其他API// 显示缓存数据大小size()// 将内存中的操作记录同步到日志文件中,不需要每次都调用flush()// 关闭,和open()对应的close()// 将所有的缓存数据清除delete()

解读journal

// 上面三个1依次是:DiskLruCache版本号,应用程序版本号,valueCountdirty: 调用edit()方法时,会向journal文件中写入一条dirty记录, 表示正准备写入,但不知道是什么结果
clean: commit()方法表示写入缓存成功, 会向journal写入一条clean记录, 代表这条脏数据被“清洗”干净了 
remove:abort()方法表示写入缓存失败, 会向journal写入一条remove记录
每一行dirty的key, 后面都应该有一行对应的clean和remove的记录, 否则这条数据就是脏的, 会被自动清理掉clean后面还会带有 此文件的字节数除了这些还有read记录, 每当我们调用get()方法获取缓存时, 都会想journal文件中写入一条read记录DiskLruCache使用了一个redundantOpCount变量来记录用户操作的次数, 当变量值达到2000就会重构journal的事件, 
保证journal文件的大小适中保持在一个合理的范围内

参考郭神的:Android DiskLruCache完全解析,硬盘缓存的最佳方案

当然还有一篇LruCache和DiskLruCache结合使用的实例:Android照片墙完整版,完美结合LruCache和DiskLruCache

总结

核心内容还是LruCache算法,通过利用LinkedHashMap,实现它最近最少使用的算法,访问过的元素加到队尾,缓存满了就去删除队首的元素,至于DiskLruCache,基本的用法是很简单的,不需要死记硬背。目前就总结这么多,有什么新的东西再总结吧。


http://www.taodudu.cc/news/show-7669524.html

相关文章:

  • android 日历控件_UI界面开发工具Calendar日历插件示例合集
  • 【模式匹配】之 —— BM算法
  • 学习笔记0714----NOSQL之redis
  • Java集合框架--HashMap
  • ORBSLAM2-ORBextractor
  • C++迭代器失效你真的理解了吗,看博主用vector的代码实现给你讲清楚迭代器失效以及解决方案!(超详细)
  • Spring Refresh
  • EIGRP的优势分析
  • EIGRP基础
  • CCNP 3 EIGRP
  • EIGRP综合实验解析
  • CCNA 6 EIGRP
  • EIGRP总结
  • EIGRP回顾
  • 3.4.2 CSMA/CD协议
  • CSMA 简介
  • 以太网 CSMA-CD与CSMA-CA的区别与工作方式
  • 【基础】static搭配inline 味道更佳(explicit_bzero-rawmemchr)
  • bzero 和 memset 的区别
  • bzero()
  • ModuleNotFoundError: No module named ‘sklearn‘
  • 成功解决ModuleNotFoundError: No module named ‘torchtext.legacy‘
  • ModuleNotFoundError: No module named ‘selenium
  • No module named ‘pyautogui‘
  • No module named ‘dataclasses‘
  • 【python基础】python导包显示No module named XXX问题
  • 记录-centos7搭建DNS服务(named.servicenamed-chroot)全流程
  • linux启动named服务失败,处理service named start失败failed_dns
  • 解决No module named pip问题
  • JPA的@NamedQuery注解