DiskLruCache 源码解析 (三)—— 写入缓存
上一篇我们看了 DiskLruCache open 方法
这篇我们看看写入缓存的过程
首先我们指定一个 cacheName 就是缓存的 key 来获取一个 editor
点进去看一下实现过程
再点进 edit 中
image.png首先看 checkNotClosed
image.png通过判断 journalWriter (Writer 类)是否为空来判断是否完成写入操作
在看 validateKey
这里用正则表达式检查 key 是否符合要求的格式 必须为数字或字母格式长度在1~64位之间
image.png继续向下 sequenceNumber 在 edit 方法中传入了固定的 ANY_SEQUENCE_NUMBER 我们暂且跳过
接下来判断 entry 是否为空 entry 是在 linkedHashMap 中通过 key 来获取的对象实体,如果不存在创建一个新的并存入 map
如果存在 并且 正在编辑中(外部已经持有一个 edit 对象) 返回空
接下来,在 entry 可用的情况下,创建一个新的 Editor 对象并将 entry 的编辑器 赋值
接下来在 journalFile 文件中写入 dirty 记录
返回 editor
接下来看看写入数据过程
首先我将 bitmap 转入 editor 的输出流中,然后调用了 editor.commit()方法
判断是否存在错误
如果存在错误 执行 completeEdit(editor,false) 并删除当前 entry
如果不存在错误 直接执行 completeEdit(editor,true)
设置 commited 为 true
completeEdit
image.png首先进行判断 传入的 editor 对应的 entry 是否与传入的 editor 匹配
不匹配抛出异常
接下来判断 传入的boolean 如果是成功 并且 entry.readable 是不可读的
循环 entry 内的所有 value 判断 written 标志为 false
执行 editor.abort() 方法并抛出异常 entry 没有 value 值
在判断 entry 的 dirtyFile 是否存在 不存在执行 abort
再向下,遍历 entry 内的所有 value
如果执行成功的 completeEdit
将 entry 的 value 中 dirty 文件 转为 clean 文件 更改entry 长度、尺寸。
如果执行的失败的 completeEdit 删除 dirty 文件
继续向下 redundantOpCount 计数+1
置空当前 entry 的 editor
如果是成功的操作 在 journalFile 中写入 CLEAN 操作行
entry.sequenceNumber=nextSequenceNumber++ 这个还不清楚 稍后再看。
如果是失败的的操作 在 journalFile 中写入 REMOVE 操作行
写入文件
判断 当前缓存容量 与 用户设置的最大容量,或者是 rebuild 请求操作
如果需要 rebuild journalFile
callable 线程 trimToSize 方法循环删除 lru 条件的 map entry
直到尺寸小于最大缓存容量
结束写入流程
总结一下:
1、获取 editor 时 会在 journal 中写入一条 dirty 记录
并在 lruMap 中创建/复用一个 entry
2、commit 方法 调用 completeEdit 方法 获取 dirtyfile 并转成 cleanfile
3、检查容量是否超出限制,如果超出执行整理操作,根据 lru 删除数据
我们还需要看一下 Entry类 这是一个 DiskLruCache 的内部类
Entry类属性的注释很清楚
image.png我们看方法列表中有两个熟悉的身影,getCleanFile() 和 getDirtyFile()
image.png我们看到 cleanFile 是一个以 key 与 value 索引命名的文件
而 dirtyFile 是一个 tmp 文件 说明
当我们缓存数据时 是先将 editor 中流的数据写入 dirty.tmp 中
确定后再转到 cleanFile 中
我们回过头在看一次 completeEdit()方法中的一段代码
写入数据 commit 时 先判断 dirty 是否存在,也就是判断一下之前是否有