本文将从源码角度,学习Glide的缓存机制。
如无特殊说明,源码版本均指:4.6.1
Glide的强大,体现在很多方面,其实缓存是一个很重要部分。Glide的缓存,分为:
(1)内存缓存:基于LruCache和弱引用机制
(2)磁盘缓存:基于DiskLruCache进行封装
Glide的缓存策略,为:
内存缓存–>磁盘缓存–>网络加载
大致流程如下:假设同时开启了内存缓存和磁盘缓存,当程序请求获取图片时,首先从内存中获取,如果内存没有就从磁盘中获取,如果磁盘中也没有,那就从网络上获取这张图片。当程序第一次从网络加载图片后,就将图片缓存到内存和磁盘上。
这两个缓存模块的作用各不相同,内存缓存的主要作用是防止应用重复将图片数据读取到内存当中,而硬盘缓存的主要作用是防止应用重复从网络或其他地方重复下载和读取数据。
内存缓存和硬盘缓存的相互结合才构成了Glide极佳的图片缓存效果。下面,将从源码角度,详细进行学习:
一. 生成缓存key
1.1 作用
缓存key是实现内存和磁盘缓存的唯一标识
1.2 原理
重写equals和hashCode方法,来确保只有key对象的唯一性
1.3 源码解析
生成缓存key的地方,在Engine的load方法中
# Engine.class
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
....
return new LoadStatus(cb, engineJob);
}
这里会调用keyFactory的buildkey方法来创建EngineKey对象,这个EngineKey也就是Glide中的缓存Key了。
可见,决定缓存Key的条件非常多,即使你只是改变了一下图片的width或者height,也会生成一个完全不同的缓存Key。
# EngineKeyFactory.class
class EngineKeyFactory {
@SuppressWarnings("rawtypes")
EngineKey buildKey(Object model, Key signature, int width, int height,
Map<Class<?>, Transformation<?>> transformations, Class<?> resourceClass,
Class<?> transcodeClass, Options options) {
return new EngineKey(model, signature, width, height, transformations, resourceClass,
transcodeClass, options);
}
}
可以发现KeyFactory的buildKey方法就是简单的返回了一个EngineKey对象。所以我们来看看这个EngineKey。
# EngineKey.class
class EngineKey implements Key {
private final Object model;
private final int width;
private final int height;
private final Class<?> resourceClass;
private final Class<?> transcodeClass;
private final Key signature;
private final Map<Class<?>, Transformation<?>> transformations;
private final Options options;
private int hashCode;
EngineKey(
Object model,
Key signature,
int width,
int height,
Map<Class<?>, Transformation<?>> transformations,
Class<?> resourceClass,
Class<?> transcodeClass,
Options options) {
this.model = Preconditions.checkNotNull(model);
this.signature = Preconditions.checkNotNull(signature, "Signature must not be null");
this.width = width;
this.height = height;
this.transformations = Preconditions.checkNotNull(transformations);
this.resourceClass =
Preconditions.checkNotNull(resourceClass, "Resource class must not be null");
this.transcodeClass =
Preconditions.checkNotNull(transcodeClass, "Transcode class must not be null");
this.options = Preconditions.checkNotNull(options);
}
@Override
public boolean equals(Object o) {
if (o instanceof EngineKey) {
EngineKey other = (EngineKey) o;
return model.equals(other.model)
&& signature.equals(other.signature)
&& height == other.height
&& width == other.width
&& transformations.equals(other.transformations)
&& resourceClass.equals(other.resourceClass)
&& transcodeClass.equals(other.transcodeClass)
&& options.