重大公告:2023年阿里云双11服务器限时大降价(1核2G1年仅需49元+2核4G1年100元) 速度点击查看!!!

Glide 的缓存原理(图片三级缓存)

3,287次阅读
没有评论

Glide 源码分析解读-缓存模块-基于最新版Glide 4.9.0

Glide

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<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中。

硬盘缓存

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类。

arison
版权声明:本站原创文章,由arison2021-08-06发表,共计4017字。
转载提示:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)