博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【笔记整理】Glide 4.9.0 的缓存机制
阅读量:3565 次
发布时间:2019-05-20

本文共 5385 字,大约阅读时间需要 17 分钟。

Glide 类中与内存缓存有关的变量Glide#memoryCache,如果用户没有通过 GlideBuilder#setMemoryCache(MemoryCache) 设置,则默认为 LruResourceCache(继承自 LruCache)。


1. 从内存缓存读取图片资源

Engine#load() 方法中,就先根据需要加载的资源的相关参数,来生成唯一的 key 值,而该值与从缓存机制有关。

// Engine.javapublic synchronized 
LoadStatus load(...) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0; // 首先根据目标资源的相关参数得到对应的 key 值 EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options); //(1)先从 ActiveResources 里面去获取 EngineResource
active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE); if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key); } return null; } // (2)如果没有,则从内存缓存中去获取 EngineResource
cached = loadFromCache(key, isMemoryCacheable); if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE); if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key); } return null; } // 在两个方法都没有获取到缓存的情况下,才会继续向下执行,从而开启线程来加载图片 ...}

(1) loadFromActiveResources()

private EngineResource
loadFromActiveResources(Key key, boolean isMemoryCacheable) {
// 先判断是否禁用内存缓存 if (!isMemoryCacheable) {
return null; } // 从 activeResources 中去获取资源 EngineResource
active = activeResources.get(key); if (active != null) {
// 标记资源被引用数量 +1 active.acquire(); } return active;}

activeResourcesActiveResources 对象,其内部有一个 HashMap<Key, ResourceWeakReference>,即持有着 key 值对应的资源对象的弱引用。

activeResources 的目的是为了 缓存正在使用中的图片,从而可以保护这些图片不会被 LruCache 算法回收掉。

(2) loadFromCache()

private EngineResource
loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null; } // 从 LruCache 对应的内存缓存中去获取 EngineResource
cached = getEngineResourceFromCache(key); if (cached != null) {
cached.acquire(); // 将取出的资源添加到 activeResources 中 activeResources.activate(key, cached); } return cached;}private EngineResource
getEngineResourceFromCache(Key key) {
Resource
cached = cache.remove(key); final EngineResource
result; if (cached == null) {
result = null; } else if (cached instanceof EngineResource) {
// Save an object allocation if we've cached an EngineResource (the typical case). result = (EngineResource
) cached; } else {
result = new EngineResource<>(cached, true /*isMemoryCacheable*/, true /*isRecyclable*/); } return result;}

loadFromCache() 则是从前面说的默认为 LruResourceCache 中去获取目标资源。如果目标资源存在,则如 LruResourceCache 中取出,并加入到前面说的 activeResources 中。

从内存缓存中读取资源的逻辑大概就是这些。概括一下来说,就是如果能从内存缓存当中读取到要加载的图片,那么就直接进行回调,如果读取不到的话,才会开启线程执行后面的图片加载逻辑。

补充,根据郭神的说的,对于内存缓存,使用到 ActiveResourcesLruResourceCache,目的是为了保护正在被使用的图片不会被 LruCache 算法回收掉。


2. 将图片资源缓存到内存

Engine 类实现了 EngineJobListener 接口,当资源加载完成后,就回调 Engine#onEngineJobComplete() 方法。

// Engine.javapublic synchronized void onEngineJobComplete(    EngineJob
engineJob, Key key, EngineResource
resource) {
// A null resource indicates that the load failed, usually due to an exception. if (resource != null) {
// 为 EngineResource 资源对象设置 ResourceListener 监听,即 Engine 对象自身, // 因为Engine 实现了 ResourceListener 接口。 resource.setResourceListener(key, this); // 如果资源允许被缓存,则将其添加到 activeResources 中 if (resource.isCacheable()) {
activeResources.activate(key, resource); } } jobs.removeIfCurrent(key, engineJob);}

这里注意的是,加载好的资源并不是直接被缓存到 LruResourceCache 中的,而是先被缓存到 activeResources 中。

而缓存到 LruResourceCache 中,则与第 7 行设置 ResourceListener 有关。之前有说过 EngineResource#acquire() 方法,该方法中就使用 EngineResource 对象的成员变量 acquired 来记录图片资源被引用的次数,调用 acquire() 方法会让变量加 1,而调用 release() 方法则会使变量减 1。

也就是说,当 acquired 变量大于 0 的时候,说明图片正在使用中,也就应该放到 activeResources 弱引用缓存当中。而经过 release() 之后,如果 acquired 变量等于 0 了,说明图片已经 不是正在被使用状态 了。

void release() {
synchronized (listener) {
synchronized (this) {
if (acquired <= 0) {
throw new IllegalStateException("Cannot release a recycled or not yet acquired resource"); } // 当 acquired 为 0 的时候就会回调设置的 ResourceListener 接口的 onResourceReleased() 方法 if (--acquired == 0) {
listener.onResourceReleased(key, this); } } }}

前面说 Engine 也实现了 ResourceListener 接口,

// Engine.javapublic synchronized void onResourceReleased(Key cacheKey, EngineResource
resource) {
activeResources.deactivate(cacheKey); if (resource.isCacheable()) {
cache.put(cacheKey, resource); } else {
resourceRecycler.recycle(resource); }}

onResourceReleased() 方法中,就会将已经不是正在被使用的图片资源从 activeResources 中移除,然后根据缓存状态,将其转移至 LruResourceCache 中,或者回收释放。


3. 关于磁盘缓存

Glide 默认在磁盘中缓存的图片并不是原始的图片,而是经过一系列操作(如压缩、转换为目标高宽)转换来的(Resource)。当然也可以设置缓存原始图片(Source)。(因而两种图片对应的 key 值也是不同的)

DiskCacheStrategy.NONE: 表示不缓存任何内容。

DiskCacheStrategy.SOURCE: 表示只缓存原始图片。
DiskCacheStrategy.RESULT: 表示只缓存转换过后的图片(默认选项)。
DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片。

磁盘缓存实现类由 InternalCacheDiskCacheFactory 创建,最终会通过缓存路径及缓存文件夹最大值创建一个 DiskLruCacheWrapper 对象。

DiskLruCacheWrapper 顾名思义是一个包装类,包装的是 DiskLruCache。且实现了 DiskCache 接口,该接口定义了磁盘缓存的操作。

另外,内部还持有 SafeKeyGenerator 对象,该对象可以根据 Key 对象得到对应的字符串 key 值,而字符串 key 就是用于索引磁盘中缓存的图片资源的。

以及,在向磁盘写入文件时(put 方法)会使用重入锁来同步代码,也就是 DiskCacheWriteLocker 类,其中主要是对 ReentrantLock 的包装。


参考文章

1、
2、

转载地址:http://yrerj.baihongyu.com/

你可能感兴趣的文章
Scala-变量和数据类型
查看>>
Scala-流程控制
查看>>
Scala-面向对象后章
查看>>
iOS蓝牙原生封装,助力智能硬件开发
查看>>
iOS 代码的Taste(品位)
查看>>
iOS开发代码规范
查看>>
iOS组件化实践(基于CocoaPods)
查看>>
数据结构之栈
查看>>
Elastic Stack简介
查看>>
关于deepin系统安装design compiler的问题解答
查看>>
hadoop3.0+spark2.0两台云服务器集群环境配置。
查看>>
网站实现qq登录(springboot后台)
查看>>
简单的用户头像修改功能(springboot后台)
查看>>
springboot+mybatis实现分页
查看>>
为什么局域网网段不同不能通信?
查看>>
认识和使用JWT
查看>>
条件表达式于运算符的点点滴滴的积累
查看>>
最短路径最基本的三种算法【此后无良辰】
查看>>
class的点点滴滴的总结
查看>>
vector 的点点滴滴的总结
查看>>