[Glide 源码分析解读-缓存模块-基于最新版Glide 4.9.0](https://www.jianshu.com/p/62b7f990ee83)
![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200307232701.png)
Glide 内部是使用 LruCache、弱引用和硬盘缓存实现的。
Glide 主要将缓存分为两块内存缓存和硬盘缓存,两种缓存的结合,构成了 Glide 缓存机制的核心。
### 内存缓存
~~~
skipMemoryCache(true)
~~~
默认是开始缓存的,如果我们不需要缓存,传入 false
内存缓存会先调用 loadFromCache 方法获取缓存,如果获取到,就直接调用 cb.onResourceReady() 方法进行回调,如果是没获取到,那么往下执行。
~~~
private EngineResource> getEngineResourceFromCache(Key key) {
Resource> cached = cache.remove(key);
final EngineResource result;
if (cached == null) {
result = null;
} else if (cached instanceof EngineResource) {
result = (EngineResource) cached;
} else {
result = new EngineResource(cached, true /*isCacheable*/);
}
return result;
}
~~~
然后会调用 loadFromActiveResources() 方法获取缓存,这个是弱引用实现的,获取到的话也直接进行回调
~~~
private EngineResource> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource> active = null;
WeakReference> activeRef = activeResources.get(key);
if (activeRef != null) {
active = activeRef.get();
if (active != null) {
active.acquire();
} else {
activeResources.remove(key);
}
}
return active;
}
~~~
如果两种都获取不到,就会开启新线程去从硬盘或者网路去加载图片。
如果我们在loadFromCache 缓存中找到了缓存,那么会将它从缓存中移除,然后将这个图片添加到 activeResources 中,activeResources 就是一个弱引用的 HashMap,用来缓存正在使用中的图片, loadFromActiveResources 就是从activeResources这个 hashmap 中取值的,这个 activeResources 就是缓存的正在使用的图片,可以保证这些图片不被 LruCache 算法回收掉。
当图片加载完成以后,会将图片加入到 activeResources 中。
在 Glide 内部有个 EngineResource 类中,一个 acquired ,记录图片是不是正在使用,如果等于 0 的时候,就代表没有使用,那么就会从 activityResource 中移除,然后添加到 LruCache 中。
以上就实现了正在使用的图片保存在 弱引用 activeResources中,而内存缓存的图片则保存在 LruCache中。
### 硬盘缓存
~~~
diskCacheStrategy(DiskCacheStrategy.NONE)
~~~
1. DiskCacheStrategy.NONE: 表示不缓存任何内容。
2. DiskCacheStrategy.SOURCE: 表示只缓存原始图片。
3. DiskCacheStrategy.RESULT: 表示只缓存转换过后的图片(默认选项)。
4. DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片。
### 当图片没变,但是 图片的链接一直在变的时候,怎么缓存?
比如使用七牛云的时候,会在图片url地址的基础之上再加上一个token参数。也就是说,一张图片的url地址可能会是如下格式:
~~~
http://url.com/image.jpg?token=d9caa6e02c990b0a
~~~
而使用Glide加载这张图片的话,也就会使用这个url地址来组成缓存Key。
但是接下来问题就来了,token作为一个验证身份的参数并不是一成不变的,很有可能时时刻刻都在变化。而如果token变了,那么图片的url也就跟着变了,图片url变了,缓存Key也就跟着变了。结果就造成了,明明是同一张图片,就因为token不断在改变,导致Glide的缓存功能完全失效了。
解决办法就是重写 GlideUrl 的 getCacheKey() 方法,把会变的一部分的值给干掉,就可以解决问题。
~~~
public class MyGlideUrl extends GlideUrl {
private String mUrl;
public MyGlideUrl(String url) {
super(url);
mUrl = url;
}
@Override
public String getCacheKey() {
return mUrl.replace(findTokenParam(), "");
}
private String findTokenParam() {
String tokenParam = "";
int tokenKeyIndex = mUrl.indexOf("?token=") >= 0 ? mUrl.indexOf("?token=") : mUrl.indexOf("&token=");
if (tokenKeyIndex != -1) {
int nextAndIndex = mUrl.indexOf("&", tokenKeyIndex + 1);
if (nextAndIndex != -1) {
tokenParam = mUrl.substring(tokenKeyIndex + 1, nextAndIndex + 1);
} else {
tokenParam = mUrl.substring(tokenKeyIndex);
}
}
return tokenParam;
}
}
//使用
Glide.with(this)
.load(new MyGlideUrl(url))
.into(imageView);
~~~
我们需要在load()方法中传入这个自定义的MyGlideUrl对象,而不能再像之前那样直接传入url字符串了。不然的话Glide在内部还是会使用原始的GlideUrl类,而不是我们自定义的MyGlideUrl类。