🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[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 缓存机制的核心。 ### 内存缓存 ```java skipMemoryCache(true) ``` 默认是开始缓存的,如果我们不需要缓存,传入 false 内存缓存会先调用 loadFromCache 方法获取缓存,如果获取到,就直接调用 cb.onResourceReady() 方法进行回调,如果是没获取到,那么往下执行。 ```java 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() 方法获取缓存,这个是弱引用实现的,获取到的话也直接进行回调 ```java private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) { if (!isMemoryCacheable) { return null; } EngineResource<?> active = null; WeakReference<EngineResource<?>> 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中。 ### 硬盘缓存 ```java diskCacheStrategy(DiskCacheStrategy.NONE) ``` 1. DiskCacheStrategy.NONE: 表示不缓存任何内容。 2. DiskCacheStrategy.SOURCE: 表示只缓存原始图片。 3. DiskCacheStrategy.RESULT: 表示只缓存转换过后的图片(默认选项)。 4. DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片。 ### 当图片没变,但是 图片的链接一直在变的时候,怎么缓存? 比如使用七牛云的时候,会在图片url地址的基础之上再加上一个token参数。也就是说,一张图片的url地址可能会是如下格式: ```java http://url.com/image.jpg?token=d9caa6e02c990b0a ``` 而使用Glide加载这张图片的话,也就会使用这个url地址来组成缓存Key。 但是接下来问题就来了,token作为一个验证身份的参数并不是一成不变的,很有可能时时刻刻都在变化。而如果token变了,那么图片的url也就跟着变了,图片url变了,缓存Key也就跟着变了。结果就造成了,明明是同一张图片,就因为token不断在改变,导致Glide的缓存功能完全失效了。 解决办法就是重写 GlideUrl 的 getCacheKey() 方法,把会变的一部分的值给干掉,就可以解决问题。 ```java 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类。