LruCache和DiskLruCache

article/2025/8/25 3:42:32

前言

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://chatgpt.dhexx.cn/article/K3E3oNle.shtml

相关文章

Android LruCache 缓存

使用场景 1、场景一&#xff1a;图片缓存利器。 可以规定缓存大小、有效避免OOM、自动移除队尾不用的图片缓存、避免HashMap各种问题。 2、场景二&#xff1a;通信缓存 从服务端需要获取数据&#xff0c;但是当访问的数据比较大&#xff0c;比较多&#xff0c;并且是重复数…

Java——LRUCache

概念 简单来说&#xff0c;由于我们的空间是有限的&#xff0c;所以发明了这个数据结构&#xff0c;当我们的空间不够添加新的元素时&#xff0c;就会删除最近最少使用的元素。 其底层逻辑通过哈希表和链表共同实现。哈希表中存储链表的每一个元素&#xff0c;方便进行元素的…

LruCache缓存

Lru算法&#xff1a; Lru 指的是“Least Recently Used-近期最少使用算法”。 1、那么LruCache到底是什么呢&#xff1f; LruCache 是对限定数量的缓存对象持有强引用的缓存&#xff0c;每一次缓存对象被访问&#xff0c;都会被移动到队列的头部。当有对象要被添加到已经达到数…

LruCache 源码解析

1. 概述 对于 Android 开发者&#xff0c;LruCache 肯定不陌生&#xff0c;几乎所有的图片缓存框架都会用到它来实现内存缓存等&#xff0c;可见 LruCache 在 Android 开发中的重要性。LRU 是 Least Recently Used 的缩写&#xff0c;近期最少使用的意思。当我们进行缓存的时候…

LruCache

LruCache这个类是通过Glide得知的&#xff0c;不过它是自己又基于LRU算法自己写了个LruCache工具类&#xff0c;不过基本原理类似&#xff0c;都是基于LRU算法实现的 1.来源 一般来说&#xff0c;缓存策略主要包含缓存的添加、获取和删除这三类操作。如何添加和获取缓存这个比…

Android基础-LruCache原理解析

一、Android中的缓存策略 一般来说&#xff0c;缓存策略主要包含缓存的添加、获取和删除这三类操作。如何添加和获取缓存这个比较好理解&#xff0c;那么为什么还要删除缓存呢&#xff1f;这是因为不管是内存缓存还是硬盘缓存&#xff0c;它们的缓存大小都是有限的。当缓存满了…

LRUCache详解

1.概念 LRU是Least Recently Used的缩写&#xff0c;意思是最近最少使用&#xff0c;它是一种Cache替换算法。 Cache的容量有限&#xff0c;因此当Cache的容量用完后&#xff0c;而又有新的内容需要添加进来时&#xff0c; 就需要挑选并舍弃原有的部分内容&#xff0c;从而腾出…

LRUCache 详解

LRU算法详解 一、什么是 LRU 算法 就是一种缓存淘汰策略。 计算机的缓存容量有限&#xff0c;如果缓存满了就要删除一些内容&#xff0c;给新内容腾位置。但问题是&#xff0c;删除哪些内容呢&#xff1f;我们肯定希望删掉哪些没什么用的缓存&#xff0c;而把有用的数据继续…

LRU Cache

前言 哈喽&#xff0c;各位小伙伴大家好&#xff0c;本章内容为大家介绍计算机当中为了提高数据相互传输时的效率而引进的一种重要设计结构叫做LRU Cache,下面将为大家详细介绍什么是LRU Cache,以及它是如何是实现的&#xff0c;如何提升效率的。 1.什么是LRU Cache? LRU是L…

uniapp日历原生插件

<template><!-- 打卡日历页面 --><view classall><view class"bar"><!-- 上一个月 --><view class"previous" click"handleCalendar(0)"><button class"barbtn">上一月</button><…

微信小程序使用日历插件

一&#xff0c;添加插件 1&#xff0c;在你的小程序关联的微信公众平台打开 设置》第三方服务》添加插件 2&#xff0c;直接AppID&#xff08;wx92c68dae5a8bb046&#xff09;搜索到该插件并申请授权&#xff0c;授权成功即可在小程序使用 二&#xff0c;小程序使用插件 app…

日历组件

日历组件&#xff1a; <template><div class"calendar" click.stop><div class"input-wrap"><inputtype"text"v-if"dateChangeSets":placeholder"placeholder"class"input dateChangeSets middle…

vue-calendar基于vue的日历插件

本文转载于https://www.cnblogs.com/zwhgithub/p/8005414.html vue-calendar-component 基于 vue 2.0 开发的轻量&#xff0c;高性能日历组件占用内存小&#xff0c;性能好&#xff0c;样式好看&#xff0c;可扩展性强原生 js 开发&#xff0c;没引入第三方库 效果 Install …

实用插件(一)日历插件——My97DatePicker

注&#xff1a;My97DatePicker插件仅限pc端使用&#xff0c;若是app项目&#xff0c;建议使用ICalendar或者Mobiscroll。 &#xff08;ICalendar插件在华为手机上存在兼容性问题&#xff0c;日期不能滚动&#xff0c;但使用很简单&#xff1b;Mobiscroll使用起来较为复杂&…

sys-calendar.js带节假日的日历插件

下载地址 sys-calendar.js带节假日的日历插件&#xff0c;代码引用比较多。 dd:

jquery日历插件,可自定义日期内容

效果图&#xff1a; 使用&#xff1a; <link href"static/css/raoCalendar.css" rel"stylesheet" type"text/css"><script src"static/js/jquery.min.js"></script> <script src"static/js/raoCalendar.js…

两款超好用js日历插件(fullcalendar和zabuto_calendar)

这两款插件特别类似,其实用其中一款即可。 先展示一下我用这两款插件制作的排班系统 这个是fullcalendar插件制作的排班页面,左边新建一系列组和组员,可以将人员直接拖拽至右边的日历上,不同组以颜色区别。 这个是将上面的排班内容用zabuto_calendar插件显示出来,黄色区域…

BootStrap日历插件

BootStrap日历插件 前端引入插件三大步骤 引入插件所需的资源文件 <%--引入BootStrap日历插件相关资源文件--%><%--按照资源文件相互依赖的顺序来引入--%><script type"text/javascript" src"jquery/jquery-1.11.1-min.js"></scrip…

jQuery实现移动端手机选择日期日历插件

效果图 calendar.css html, body {color: #333;margin: 0;height: 100%;font-family: "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;font-weig…

uniapp日历插件

日历插件 效果图一、使用方法二、组件编写&#xff0c;两个文件、直接上代码month.vuecalendar.vue 效果图 一、使用方法 <template><view><view class"" click"open"><text>展示日历{{value[0]}}-{{value[1]}}</text><…