1. 简介
Glide缓存分为两部分,分别为内存缓存和硬盘缓存。其中内存缓存的主要作用是防止应用重复地将图片数据读取到内存中,而硬盘缓存的主要作用是防止应用重复从网络或其他地方重复下载和读取数据。
内存缓存和硬盘缓存的配合才实现了Glide极佳的图片缓存效果。
2. 缓存Key
大家都知道,如果想缓存一个东西的话,必然会有对应的缓存key。那么Glide的缓存key在哪呢?
首先我们来看下Engine.load()
方法:
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
// 判断是否为主线程
Util.assertMainThread();
// 获取当前时间
long startTime = LogTime.getLogTime();
// 生成key,包括id、width、height、signature以及decoder等参数
final String id = fetcher.getId();
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
// -----------读取内存缓存-----------
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
// -----------runnable中会先读取磁盘缓存-----------
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
我们现在需要关注的核心就是10-13行的代码。可以看到,他在10行调用了fetcher.getId()方法获得了一个id字符串,这个字符串也是我们要加载图片的唯一标识,比如说我们要从网络读取,那图片的Url就是他的id。
接下来,通过id、signature、width、height等一些列参数传入EngineKeyFactory的buildKey()
方法当中,从而构建出了一个EngineKey对象。这个对象就是Glide的缓存key了。
3. 内存缓存
首先我们来看下Glide如何使用图片缓存。
3.1 用法
内存缓存Glide是默认开启的。
也就是说,当我们使用Glide加载一张图片之后,这张图片就会被缓存到内存当中,只要她还没从内存中被清除,下次使用Glide加载这张图片都会直接从内存中读取。这样无疑可以大幅度提升图片的加载效率。
那么既然是默认开启的,怎样才可以关闭他呢?
Glide对此也提供了方法:
Glide.with(this)
.load(url)
.skipMemoryCache(true)
.into(imageView);
通过skipMemoryCache()
API 就可以关闭它。
3.2 源码
说起缓存,大家一定第一反应就是LRUCache。没错,内存缓存就是通过LRUCache实现的,但是他除了LRUCache之外,还有一种弱引用缓存。那就让我们通过源码来分析下:
还记得我们在讲Glide请求源码load()
的时候,分析到在loadGeneric()
方法中会调用Glide.buildStreamModelLoader()
方法来回去一个ModelLoader对象,我们现在来看下他的源码:
public static <T> ModelLoader<T, InputStream> buildStreamModelLoader(Class<T> modelClass, Context context) {
return buildModelLoader(modelClass, InputStream.class, context);
}
可以看到这个方法直接调用了buildModelLoader()
方法,我们再来看看这个方法:
public static <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass,
Context context) {
if (modelClass == null) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Unable to load null model, setting placeholder only");
}
return null;
}
return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass);
}
核心代码就是return那一句,可以看到他先调用了一个Glide.get()
方法,而这个方法就是关键:
public static Glide get(Context context) {
// 懒汉单例模式
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
// 构造对象之前的一些配置
Context applicationContext = context.getApplicationContext();
List<GlideModule> modules = new