分析Glide缓存策略我们还得从之前汾析的Engine#load方法入手,这个方法中展示了缓存读取的一些策略,我们继续贴上这块代码
涉及到的缓存类型如下:
内存和磁盘各自的两种缓存
-
DiskCache,磁盘缓存比较简单其中也分为Resourc手机GlideCache是什么Key与DataCacheKey,一个是已经decode过的可以之间供Target给到View去渲染的另一个是还未decode過的,缓存的是源数据磁盘缓存的保存是在第一次请求网络成功时候,会刷新磁盘缓存此时处理的是源数据,至于是否会缓存decode过后的數据取决于DiskCacheStrategy的策略。
结合前面所有文章这里我再次简要梳理下资源加载的过程。
- 检查ActiveResources缓存中能否命中若命中,則请求完成通知Target渲染对应的View。若未命中则进入Step2。
- 检查MemoryCache缓存能否命中若命中,则请求完成通知Target渲染对应的View。若未命中则进入Step3。
SourceGenerator優先级顺序不管哪种方式取到了数据,最终都会回调至DecodeJob中处理区别在于SourceGenerator会更新磁盘缓存,此时的是DataCacheKey类型的缓存进入步骤4。
在一文中我们看到资源加载成功缓存到磁盘上是在SourceGenerator#cacheData方法中进行的,我们来看其具体实现
这段代码逻辑相关仳较好理解,根据loadData中的sourceKey以及签名信息构造一个DataChcheKey类型的对象,而后将其put至磁盘缓存中其中sourceKey就是我们加载资源的GlideUrl对象()。
磁盘缓存的具体实現我们已经了解默认是由DiskLruCacheWrapper实现,具体功能就是将数据写入预先设置的缓存目录的文件下以文件的方式存放。在分析D加载资源的详细过程中我们知道Engine#load会先在内存中查找是否有缓存命中,否则会启动DecodeJob在它中总共有三个DataFetchGenerator,这里和磁盘缓存相关的就是DataCacheGenerator具体逻辑是在其DataCacheGenerator#startNext方法Φ。
我们假定内存缓存以及在激活的资源池中均没有命中则此时会根据GlideUrl[
可以看到,真正去根据key获取文件信息实际上是由getDiskCache().get方法去实现的這里我们需要分析getDiskCache()的实现,也就是操作磁盘文件的类了
我们分析最简单的情况,如果在磁盘中有缓存文件了显然此时if语句journalFile文件是存在嘚,因此接下来调用readJournal根据缓存key将索引信息读入lruEntries中,每一个缓存key对应有一个Entry信息Entry中保存缓存文件索引的是cleanFiles,cleanFiles虽然是一个File数组但是目前glide對于这个数据的size是恒为1的,也就是缓存key,Entry,文件是一个一一对应的关系这里glide用数组提供了将来一种可扩展性的预留实现。这样磁盘缓存索引也就建立完成下面继续看DiskLruCache#get的实现
正如我们简单的例子,这里DataCacheKey只有网络的url决定也即是一个数据流对象,不同的decode可以来扩展它Resourc手機GlideCache是什么Key就是这样一种缓存。至此对于Glide的缓存架构我们就分析完了,整个系列差不多也接近尾声了后面文章中,我会整理一些大纲的總线供大家自己研读。
}
可以看到类似MD5编码命名的文件就是缓存的图片文件了然后我们看到还有一个叫做journal的文件,journal一般会用做为操作日志我们尝试以文本文件打开它。
再没看源码的情况下也能大概猜到这些操作的功能,接下来我们通过源码对LRUDiskCache做一个理性的认识
首先我们来复习一下LinkedHashMap的作用,以及其使用场景
LinkedHashMap内部维护了一个双链表,用来保证元素的访问顺序固定
LinkedHashMap
有这样一个构造函数,最后一个参數 accessOrder
当 accessOrder
为true时候表示链表已访问顺序排序,最后访问的元素将会放到链表的末尾;当 accessOrder
为false时表示元素访问顺序为插入顺序
这样根据传入参数嘚不同就可用LinkedHashMap实现不同的算法:
accessOrder=false
FIFO,最先插入的元素在链头最后插入的元素在链尾,实现了队列的功能
很显然我们使用的是LinkedHashMap的LRU特性,我們把accessOrder设置为true从头开始遍历即访问到的元素即是最少访问的元素。
DiskLruCache 如何保证磁盘缓存不超过最大值
以上这段代码就是保证磁盘缓存size的核心代码利用了LinkedHashMap的accessOrder的特性实现LRU,移除访问最少的entity
其中第一行固定为libcore.io.DiskLruCache;第二行是DiskLruCache的版本,目前固定為1;第三行表示所属应用的版本号;第四行valueCount表示一个缓存key可能对应多少个缓存文件它决定了后面一个CLEAN状态记录最多可以size大小数据;第五荇是空行。此后记录的就是DiskLruCache针对磁盘缓存的操作记录了其中几个状态表示如下:
CLEAN 表示缓存处于一个稳定状态,即当前没有对该缓存数据進行写操作在该状态下,对缓存文件的读写都是安全的
DIRTY 表示当前该key对应的缓存文件正在被修改,该状态下对缓存文件的读写都是不安铨的需要阻塞到对文件的修改完成,使该key对应的状态转变成CLEAN为止
REMOVE 表示该key对应的缓存文件被删除了,在缓存整理的过程中可能会出现多條这样的记录
READ 表示一个对key对应的缓存文件进行读取的操作记录。
每个操作记录状态后面都有一个字符串表示缓存的key,其中CLEAN状态在后面還会有一个或者多个数字这些数字表示对应缓存文件的大小。之所以允许一个key对应多个文件主要是考虑到满足类似于一张图片可能存茬多个大小和分辨率不同的缓存的功能。
根据存储结构的不同我们知道DiskCache不能像MemoryCache一样是一整块的,一整块的文件操作就会存茬文件内部的有效数据移动操作这样反而效率很低;所以将每个图片单独缓存到文件中,便于删除
从 DiskLruCache
的源码可以看出,DiskLruCache
实际上就是一個文件管理器添加了LRU策略的文件管理器。并通过journal文件保存缓存文件的操作记录配合LinkedHashMap实现LRU策略。
删除超出size的缓存文件添加REMOVE操作记录,並且提交线程池重构journal文件
以上即完成了DiskLruCache的LRU策略的本地文件缓存功能,希望我的解析能够让你能快速理解Glide的磁盘缓存策略的实现
}