DiskLRUCache

DiskLRUCache是Android中实现磁盘缓存相关的组件类,当缓存满时其使用最近最少使用策略来淘汰相关的元素,以控制缓存大小。本文主要基于DiskLRUCache相关源码分析DiskLRUCache的创建、缓存的添加、获取、删除流程。

DiskLRUCache创建

DiskLRUCache不允许直接创建,可以通过调用open方法去创建

	public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)throws IOException {if (maxSize <= 0) {throw new IllegalArgumentException("maxSize <= 0");}if (valueCount <= 0) {throw new IllegalArgumentException("valueCount <= 0");}File backupFile = new File(directory, JOURNAL_FILE_BACKUP);if (backupFile.exists()) {//如果备份的目录文件存在,尝试获取目录文件,如果目录文件存在,旧删除备份目录文件,如果不存在就将备份目录文件重命名为目录文件。File journalFile = new File(directory, JOURNAL_FILE);if (journalFile.exists()) {backupFile.delete();} else {renameTo(backupFile, journalFile, false);}}// 创建DiskLruCache对象DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);if (cache.journalFile.exists()) {try {//读取并解析目录文件cache.readJournal();cache.processJournal();return cache;} catch (IOException journalIsCorrupt) {cache.delete();}}}

其创建时的参数说明如下:

  1. directory: 缓存目录,
  2. appVersion: app版本,当appVersion更新后, 会自动清除老数据,一般我们是不需要清除老数据的,所以一般这个不变。
  3. valueCount: 一个节点对应的文件数
  4. maxSize:缓存大小

open方法主要做了三件事:

  1. 确认目录文件
  2. 创建DiskLruCache对象
  3. 读取目录文件内容到内存

那目录文件到底是啥样的呢?如下

     *     libcore.io.DiskLruCache*     1*     1*     1**     CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054*     DIRTY 335c4c6028171cfddfbaae1a9c313c52*     CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342*     REMOVE 335c4c6028171cfddfbaae1a9c313c52*     DIRTY 1ab96a171faeeee38496d8b330771a7a*     CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234*     READ 335c4c6028171cfddfbaae1a9c313c52*     READ 3400330d1dfc7f3f7f4b8d4d803dfcf6

我们来分别对每一行进行分析吧:
1、想都不用想,就是告诉我们该缓存用的是DiskLruCache。
2、DiskLruCache的版本号。
3、应用程序的版本号。
4、在DiskLruCache.open()方法中传入,表示一个key可以对应几个缓存文件,一般我们都传1,表示一key一Value。
5、DIRTY开头,后面紧跟md5编码的key值,也就是缓存文件的名字,表示我们正在向缓存文件中写入一条数据,缓存文件的名字为后面的key值,可能写入成功,也可能写入失败,故标记为dirty。
6、CLEAN开头,后面紧跟缓存文件的名称,表示该数据写入成功了,再后面又有一组数字,其实该组数字是我们写入的数据字节大小,比如我们写入的是图片,那说明该图片的大小为17352个字节。
7、READ开头,后面紧跟缓存文件的名称,表示我们读取了该名称的缓存文件的数据。
在创建DiskLruCache前会将目录文件中每一行读入内存,实际上每一行的操作指令就是访问顺序,根据Dirty/Clean/Read/Remove操作符来调用对应Entry的插入删除等操作,以此来构建最近最少使用记录。

添加缓存

添加缓存主要通过Editor获取对应文件流,然后写入内容后调用commit,获取Ediitor时有2个操作

  1. 通过key获取一个Editor,此操作会先去lruEntries中获取Entry节点,没有的话会自动创建一个Entry节点,并给该节点绑定一个Editor对象。
  2. 向目录文件写入DIRTY操作指令
 	public Editor edit(String key) throws IOException {return edit(key, ANY_SEQUENCE_NUMBER);}private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {checkNotClosed();Entry entry = lruEntries.get(key);if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null|| entry.sequenceNumber != expectedSequenceNumber)) {return null; // Value is stale.}if (entry == null) {entry = new Entry(key);lruEntries.put(key, entry);} else if (entry.currentEditor != null) {return null; // Another edit is in progress.}Editor editor = new Editor(entry);entry.currentEditor = editor;// Flush the journal before creating files to prevent file leaks.journalWriter.append(DIRTY);journalWriter.append(' ');journalWriter.append(key);journalWriter.append('\n');journalWriter.flush();return editor;}

获取到Editor对象后,可以通过getFile方法获取对应文件File对象,通过OutputStream写入到文件中,然后调用commit方法。

  public File getFile(int index) throws IOException {synchronized (DiskLruCache.this) {if (entry.currentEditor != this) {throw new IllegalStateException();}if (!entry.readable) {written[index] = true;}File dirtyFile = entry.getDirtyFile(index);if (!directory.exists()) {directory.mkdirs();}return dirtyFile;}}

获取缓存

调用get方法获取缓存,会返回一个Snapshot对象,该对象存储对应key和缓存文件的InputStream,并且向目录文件中写入Read标签的记录。

  public synchronized Snapshot get(String key) throws IOException {//通过key获取到对应的EntryEntry entry = lruEntries.get(key);if (entry == null) {return null;}InputStream[] ins = new InputStream[valueCount];try {for (int i = 0; i < valueCount; i++) {ins[i] = new FileInputStream(entry.getCleanFile(i));}} catch (FileNotFoundException e) {return null;}redundantOpCount++;journalWriter.append(READ + ' ' + key + '\n');if (journalRebuildRequired()) {executorService.submit(cleanupCallable);}return new Snapshot(key, entry.sequenceNumber, ins, entry.lengths);}public final class Snapshot implements Closeable {private final String key;private final long sequenceNumber;private final InputStream[] ins;private final long[] lengths;}

删除缓存

删除缓存主要涉及三件事:

  1. 从map中删除该节点
  2. 向目录文件中心写入REMOVE标签
  3. 重新计算当前缓存的大小
public synchronized boolean remove(String key) throws IOException {checkNotClosed();validateKey(key);Entry entry = lruEntries.get(key);if (entry == null || entry.currentEditor != null) {return false;}for (int i = 0; i < valueCount; i++) {File file = entry.getCleanFile(i);if (file.exists() && !file.delete()) {throw new IOException("failed to delete " + file);}//调整缓存大小size -= entry.lengths[i];entry.lengths[i] = 0;}redundantOpCount++;journalWriter.append(REMOVE + ' ' + key + '\n');lruEntries.remove(key);if (journalRebuildRequired()) {//cleanupCallable这个执行的时候会调用trimToSize方法,执行超出最大容量后的最老节点的移除executorService.submit(cleanupCallable);}return true;}private void trimToSize() throws IOException {while (size > maxSize) {Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();remove(toEvict.getKey());}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/33993.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

暗影精灵8Pro声音没有了,这个方法可以解决,亲测有效!

这个OMEN by HP Gaming Laptop 16-k0xxx Windows 10 Sound Driver Mod &#xff0c;真的解决了我的大问题&#xff01; 如果你的暗影精灵8 Pro酷睿版突然变得哑巴了&#xff0c;扬声器和麦克风都发不出声音&#xff0c;那可能是声卡驱动出了问题。 别担心&#xff0c;我也是个…

代码随想录算法训练营DAY46|121. 买卖股票的最佳时机、122.买卖股票的最佳时机II、123.买卖股票的最佳时机III

121. 买卖股票的最佳时机 题目链接&#xff1a;121. 买卖股票的最佳时机 class Solution(object):def maxProfit(self, prices):""":type prices: List[int]:rtype: int"""if len(prices) 0:return 0dp [[0]*2 for i in range(len(prices))]…

eNSP中三层交换机的配置和使用

一、拓扑图 1.新建拓扑图 2.PC端配置 PC1: PC2&#xff1a; 二、基本命令配置 1.S1配置 <Huawei>system-view [Huawei]sysname S1 [S1]vlan 10 //在交换机 S1 上创建 VLAN 10 [S1-vlan10]vlan 20 // 在交换机 S1 上创建 VLAN 20 [S1-vlan20]quit //退出 VLAN 配置…

舆论中心的《黑神话:悟空》:人们总希望,这只猴子能打破些什么

距离《黑神话&#xff1a;悟空》上线还有60天。外界关于游戏的争议有很多&#xff0c;但游戏科学却很少出来回应什么。 6月9日&#xff0c;博主兲虎发文称&#xff0c;《黑神话&#xff1a;悟空》之所以在发布宣传视频后&#xff0c;一直遭受到所谓性别歧视的攻击与污蔑&#…

短视频营销系统小程序源码

开启全新营销时代 &#x1f3a5;一、引言&#xff1a;短视频营销微信小程序&#xff0c;营销新风尚 在数字化时代&#xff0c;短视频以其直观、生动的特点迅速崛起&#xff0c;成为用户获取信息、娱乐消遣的重要渠道。而短视频营销微信小程序则是将短视频与微信营销完美结合&…

力扣(2024.06.25)

1. 76——最小覆盖子串 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 "" 。 注意&#xff1a; 对于 t 中重复字符&#xff0c;我们寻找的子字符串中该字符数量必须不…

【Unity】数据持久化--二进制 ,文件操作

1、各字节类型转字节数组 1.1 不同变量类型 有符号 sbyte int short long无符号 byte uint ushort ulong浮点 float double decimal特殊 bool char string 1.2 变量的本质 变量的本质是2进制在内存中都以字节的形式存储着1byte 8bit1bit(位)不是0就是1 //通过sizeof方法可…

解决node: bad option: -V

出现这个问题是由于我们的不当操作造成的&#xff0c;v是需要小写的&#xff0c;看下图 node --version node -v

P2P文件传输协议之BitTorrent协议

P2P文件传输协议中的BitTorrent协议是一种用于高效地下载和上传大型文件的点对点&#xff08;P2P&#xff09;传输协议。以下是关于BitTorrent协议的详细说明&#xff1a; 一、技术原理 分布式系统&#xff1a;BitTorrent是一个分布式系统&#xff0c;没有中央服务器。相反&a…

缓存双写一致性(笔记)

缓存更新方案 旁路缓存模式 这是比较多的 旁路缓存模式&#xff1a;缓存有就返回&#xff0c;没有数据库查询&#xff0c;放入缓存返回。 还有些常用缓存策略 读穿透模式 读穿透和旁路很相似&#xff0c;程序不需要关注从哪里读取数据&#xff0c;它只需要从缓存查询数据。…

MySQL中什么是索引合并?

索引合并是数据库查询优化的一种技术&#xff0c;它允许数据库管理系统在处理查询时&#xff0c;利用多个索引来改进数据检索的效率。这种技术主要应用在那些设计多个条件的查询中&#xff0c;通过合并多个索引的结果集&#xff0c;找出最终满足所有条件的数据行。 在MySQL中如…

ts 中定义多个数据

let a :{name:string,[xx:string]:any} a {name:小明,age:28,gender:男} 正确 a {name:111,age:28,gender:男} 错误&#xff0c;name必须是字符串 //这句话的意思就是a对象中 name是必填的并且只能是字符串&#xff0c;后面属性名是字符串&#xf…

从概念到现实:数字孪生技术在智慧充电站的实践

在电动汽车蓬勃发展的今天&#xff0c;充电基础设施的智能化升级成为了推动新能源汽车产业跃进的关键一环。数字孪生技术&#xff0c;作为智能制造和工业4.0的核心&#xff0c;正在逐渐渗透到智慧充电站的每一个角落——从提高能源效率到增强用户体验&#xff0c;为智慧充电站的…

vuex数据持久化

清空原因&#xff1a; 刷新页面vuex的数据会丢失属于正常现象&#xff0c;因为JS的数据都是保存在浏览器的堆栈内存里面的&#xff0c;刷新浏览器页面&#xff0c;以前堆栈申请的内存被释放&#xff0c;这就是浏览器的运行机制&#xff0c;那么堆栈里的数据自然就清空了。 解…

【快慢指针】个人练习-Leetcode-142. Linked List Cycle II

题目链接&#xff1a;https://leetcode.cn/problems/linked-list-cycle-ii/description/ 题目大意&#xff1a;给一个链表的头部&#xff0c;判断链表是否有环&#xff0c;如果有&#xff0c;返回环的第一个指针&#xff1b;如果没有&#xff0c;返回nullptr 思路&#xff1a…

强化学习-RLHF-PPO入门

一、定义 强化学习微调分类RM模型 数据集格式训练流程Reward 模型训练流程(分类模型&#xff0c;积极为1&#xff0c;消极为0) AutoModelForSequenceClassificationReward 模型训练案例PPO模型训练流程PPO模型训练案例 二、实现 强化学习微调分类 RLHF:基于人类反馈对语言模型…

python,ipython 和 jupyter notebook 之间的关系

python&#xff0c;ipython 和 jupyter notebook 之间的关系 文章目录 python&#xff0c;ipython 和 jupyter notebook 之间的关系1. Python2. IPython3. Jupyter Notebook启动 Jupyter Notebook 关系总结 Python、IPython 和 Jupyter Notebook 是相互关联但具有不同功能的工具…

机器学习之数学基础(七)~过拟合(over-fitting)和欠拟合(under-fitting)

目录 1. 过拟合与欠拟合 1.1 Preliminary concept 1.2 过拟合 over-fitting 1.3 欠拟合 under-fitting 1.4 案例解析&#xff1a;黑天鹅 1. 过拟合与欠拟合 1.1 Preliminary concept 误差 经验误差&#xff1a;模型对训练集数据的误差。泛化误差&#xff1a;模型对测试…

【可控图像生成系列论文(四)】IP-Adapter 具体是如何训练的?1公式篇

系列文章目录 【可控图像生成系列论文&#xff08;一&#xff09;】 简要介绍了 MimicBrush 的整体流程和方法&#xff1b;【可控图像生成系列论文&#xff08;二&#xff09;】 就MimicBrush 的具体模型结构、训练数据和纹理迁移进行了更详细的介绍。【可控图像生成系列论文&…

RabbitMQ 消息传递

消息何去何从 mandatory和immediate是channel.basicPublish方法中的两个参数&#xff0c;他们都有当消息传递过程中不可达目的地时将消息返回给生产者的功能。RabbitMQ提供的备份交换器可以将未能被交换器路由的消息&#xff08;没有绑定队列或者没有匹配的绑定&#xff09;存…