是文件缓存的管理对象,使用 LRU 算法对保存在永久存储设备上的缓存文件进行管理。
比手机的闪存更低速的访问设备是网络,文件缓存的意义就在于通过重复利用缓存的数据,减少网络请求,减少网络流量,提高响应速度。
static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
来创建 DiskLruCache
对象。
close()
关闭,见 [4.]DiskLruCache.Snapshot get(String key)
获取一个 DiskLruCache.Snapshot
对象,再通过这个对象进行读取操作。DiskLruCache.Snapshot
,其实就是这个 key
对应的相关数据,主要是多个文件的输入流和大小,多个文件的数量对应构造方法里的 valueCount
。Snapshot.getLength(int index)
获取文件大小,进行一些判断。Snapshot.getInputStream(int index)
获取一个 InputStream
,可以用来读取文件内容,注意这个流不是缓存流,如果需要缓存流可以创建 BufferedInputStream
包装一下 InputStream
。InputStream
需要手动关闭,既可以直接关闭 InputStream
,也可以调用 Snapshot.close()
来关闭属于它的所有 InputStream
。DiskLruCache.Editor edit(String key)
方法获取一个 DiskLruCache.Editor
对象,再通过这个对象进行写入操作。DiskLruCache.Editor
,其实就是将写入相关的一些操作抽象处理,对这个对象的操作都对应 key
关联的缓存文件。Editor
对象是通过 key
获取的,edit
方法将返回 null。保证同时只有一个 Editor
对象在对同一个 key
进行写入操作。因此调用之后需要判断一下。OutputStream newOutputStream(int index)
创建输出流来写入数据,注意这个流不是缓存流,如果需要缓存流可以创建 BufferedOutputStream
包装一下 OutputStream
。OutputStream
需要手动关闭。Editor
设置结果。如果写入操作和相关业务成功了,缓存文件有效,则调用 Editor.commit()
方法表示缓存写入成功。如果写入操作或相关业务失败了,缓存文件无效,则调用 Editor.abort()
来还原为未获取 Editor
之前的状态。DiskLruCache
管理多个 Entry(key-values),因此锁粒度应该是 Entry 级别的。get
和 edit
方法都是同步方法,保证内部的 Entry Map 的安全访问,是保证线程安全的第一步。get
和 edit
方法都返回一个对象来关联某个 Entry
edit
方法内部保证不会有两个 Editor
同时关联一个 Entry。直接利用方法本身的锁就达到了目的。DiskLruCache
可以同时读写同一个 key,使用的策略是:get
返回后,就像返回值类型 Snapshot
的词义暗示的那样,它是一个快照对象,再对这个 Entry 进行任何操作都不会影响快照对象,快照对象在返回的时候就固定了,关联的输入流也一样。commit
方法,commit
方法是原子操作,多个 value 的修改要么同时不可见,要么同时可见。[a-z0-9_-]{1,64}
,在实际使用中,可以用 md5 的方法将 url 转换为符合条件的字符串。DiskLruCache
缓存,不能再用作别的目的,因为 DiskLruCache
可能会删除或覆盖其中的文件。DiskLruCache 内部使用一个 journal 文件来记录和管理缓存文件。文件内容大概长这样:
libcore.io.DiskLruCache
1
100
2
CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
DIRTY 335c4c6028171cfddfbaae1a9c313c52
CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
REMOVE 335c4c6028171cfddfbaae1a9c313c52
DIRTY 1ab96a171faeeee38496d8b330771a7a
CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
READ 335c4c6028171cfddfbaae1a9c313c52
READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
journal 文件记录了一些元信息,比如版本号什么的。
journal 文件还记录了每个 Entry 的数据,有四种状态:
Entry 数据并不是在记录的位置“原地”修改,而是不停地添加新的状态到文件末尾,只有读取到最新的一条 Entry 相关的记录才能知道它的最新状态。随着操作越来越多,DiskLruCache 也会执行压缩,删除之前的状态。