一、Glide缓存初识
在上两篇文章中,我们从源码角度分析Glide框架加载图片的流程、以及Glide图片通过巧妙的空view的Fragment的设计实现的Glide的图片加载的三大生命周期函数onStart、onStop、onDestroy。Glide的框架的源码量确实比较大,今天我们再详细分析一下,Glide的框架的缓存模块的设计。
默认情况下,Glide 会在开始一个新的图片请求之前检查以下多级的缓存:
- 活动资源 (Active Resources) - 现在是否有另一个 View 正在展示这张图片?
- 内存缓存 (Memory cache) - 该图片是否最近被加载过并仍存在于内存中?
- 资源类型(Resource) - 该图片是否之前曾被解码、转换并写入过磁盘缓存?
- 数据来源 (Data) - 构建这个图片的资源是否之前曾被写入过文件缓存?
前两步检查图片是否在内存中,如果是则直接返回图片。后两步则检查图片是否在磁盘上,以便快速但异步地返回图片。
如果四个步骤都未能找到图片,则Glide会返回到原始资源以取回数据(原始文件,Uri, Url等)。
上述这段描述来源于官方文档对于缓存的介绍。官方文档的介绍,已经很清晰的说明了Glide框架在缓存实现的策略。缓存的类型在这里被分为了四类:活动资源、内存缓存、资源类型(磁盘缓存)、数据来源(文件缓存)。
其中活动资源、内存缓存 均属于内存缓存范畴、资源类型、数据来源 均属于磁盘缓存范畴。接下来,我们就从源码角度,来看一下这四级缓存的实现。
二、四级缓存实现的源码分析
结合之前的两篇Glide的分析的文章,我们确认缓存的分析的入口方法为Engine.load的方法,接下来我们就直接再次查看Engine类的相关源码实现:
2.1 活动资源的获取和添加
/** Engine类的功能:对启动的一个加载做响应和管理者活动资源和缓存资源 */
public class Engine imp... {
public <R> LoadStatus load(...) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//key的创建,一份资源(比如图片)的唯一标识
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
//从内存中获取资源
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
//memoryResource=null,表示活动资源、内存缓存均未获取到
if (memoryResource == null) {
//等待已经存在或者启动一个新的job
return waitForExistingOrStartNewJob(
....);
}
}
//从内存中获取资源
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
//是否启动内存缓存,构建glide的时候可以配置,无的的则直接返回空
if (!isMemoryCacheable) {
return null;
}
//根据key从活动资源中获取
EngineResource<?> active = loadFromActiveResources(key);
//活动资源不为空
if (active != null) {
//将活动资源返回
return active;
}
//活动资源为空,从cache中获取
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
//cache资源不为空,将cache资源返回
return cached;
}
//活动资源和cache资源都为空,则最终返回null
return null;
}
}
从上述源码中,主要看loadFromMemory()方法的实现,流程上,先从活动内存获取缓存,如果获取到直接向上层返回,如果获取不到从cache缓存中获取,如果获取到将cache缓存返回,获取不到则返回空。接下来分别具体看活动缓存和cache缓存的究竟:
private final ActiveResources activeResources;
@Nullable
private EngineResource<?> loadFromActiveResources(Key key) {
EngineResource<?> active = activeResources.get(key);
if (active != null) {
//这个方法是在引擎的resource中定义的,做引用计数
active.acquire();
}
return active;
}
/**
* 资源包装器
*/
class EngineResource<Z> implements Resource<Z> {
//获得引用数
synchronized void acquire() {
if (isRecycled) {
throw new IllegalStateException("Cannot acquire a recycled resource");
}
//获得活动资源引用数+1
++acquired;
}
//释放引用数
void release() {
boolean release = false;
synchronized (this) {
if (acquired <= 0) {
throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
}
if (--acquired == 0) {
release = true;
}
}
if (release) {
//从活动缓存中释放、迁入cache缓存中
listener.onResourceReleased(key, this);
}
}
}
@Override
public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
activeResources.deactivate(cacheKey);
if (resource.isMemoryCacheable()) {
//迁入cache缓存
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource, /*forceNextFrame=*/ false);
}
}
活动资源是谁来维护的,我们可以看到activeResources.get(key),ActivityResources是活动资源的维护对象,ActivityResources是啥你,追踪一下源码:
final class ActiveResources {
private final boolean isActiveResourceRetentionAllowed;
private final Executor monitorClearedResourcesExecutor;
//value 为弱引用对象Map集合
@VisibleForTesting final Map<