前言
在前面一篇文章中,主要分析了Glide的工作流程,以加载网络图片为例分析了Glide是如何工作的。在熟悉了Glide的工作流程后,我们就可以及继续一些细节的分析。接下来,针对Glide的缓存策略进行分析。
我们知道,一个高效的图片框架是少不了缓存的,使用缓存可以减少资源的重复加载,提高资源的利用率。在Glide中,缓存分为两大类:内存缓存以及硬盘缓存。具体到缓存类型可以分为4种,一下是官网给出的缓存类型。
- 活动资源 (Active Resources) - 现在是否有另一个 View 正在展示这张图片?
- 内存缓存 (Memory cache) - 该图片是否最近被加载过并仍存在于内存中?
- 资源类型(Resource) - 该图片是否之前曾被解码、转换并写入过磁盘缓存?
- 数据来源 (Data) - 构建这个图片的资源是否之前曾被写入过文件缓存?
可以看到,内存缓存分为活动资源以及内存资源;硬盘缓存分为是否有处理过的资源以及原图资源。接下来主要从缓存的更新以及如何缓存两方面分析。
Glide的缓存
缓存键
缓存键是查找的缓存的一个键值,在Glide中需要根据资源的信息构造缓存键,然后查找缓存资源。在分析Glide的工作流程时,在类Engine中开始加载资源时,我们可以看到构造缓存键。
public <R> LoadStatus load(/**省略参数**/) {
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
}
在Engine的load()方法中可以看到在生成EngineKey的过程中用到了很多参数,比如model资源途径、signature签名、宽高等。这多种参数共同决定了缓存键的生成。
内存缓存
上面说到内存缓存分为活动资源和内存资源(这里先将另外一种资源称为内存资源)。其中活动资源是正在使用的图片也就是正在View中展示的,内存资源是存在内存中的,没有在使用。可以看到,Glide在内存缓存这里将资源又分为了两类。
我继续从Engine的load()方法分析。这里是真正开始加载资源的入口。
public <R> LoadStatus load(/**省略参数**/) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
//从内存中加载资源
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(/**省略参数**/);
}
}
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
从代码里可以看到Glide先从内存中加载资源,这里调用了loadFromMemory()方法。
private EngineResource<?> loadFromMemory(EngineKey key, boolean isMemoryCacheable, long startTime) {
//这里是一个配置,使用skipMemoryCache(boolean skip)可以选择是否跳过从缓存中获取资源
if (!isMemoryCacheable) {
return null;
}
//从活动资源中取缓存
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
return active;
}
//从内存资源中取缓存
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
return cached;
}
return null;
}
可以看到,在上面的过程中,Glide是先从活动资源取缓存,如果没有相应的活动资源就从内存资源中取缓存。接着往下看。
private EngineResource<?> loadFromActiveResources(Key key) {
EngineResource<?> active = activeResources.get(key); //取出活动资源
if (active != null) {
active.acquire();
}
return active;
}
在代码可以看到是从activeResources取出的活动资源。我们在这里跟一下这变量可以看到是在Engine的构造函数中进行的初始化。activeResources是ActiveResources类型的变量。我们直接在类ActiveResources看接下来的逻辑。
final class ActiveResources {
@VisibleForTesting final Map<Key, ResourceWeakReference> ac