Android图片加载的那些事:为什么你的Glide缓存没有起作用?


前言

  • Glide,该功能非常强大 Android 图片加载开源框架 相信大家并不陌生

    Github截图

  • 正由于他的功能强大,所以它的源码非常复杂,这导致很多人望而却步

  • 本人尝试将 Glide 的功能进行分解,并单独针对每个功能进行源码分析,从而降低Glide源码的复杂度。

接下来,我将推出一系列关于 Glide的功能源码分析,有兴趣可以继续关注

  • 今天,我将主要讲解在使用Glide缓存功能时的问题:为什么Glide 的缓存无起作用,希望你们会喜欢。

请先阅读文章:Android:深入剖析图片加载库Glide缓存功能(源码分析)


1. 背景

  • Glide实现内存 & 磁盘缓存是根据 图片的缓存Key进行唯一标识
  • 开发者为了降低成本 & 安全,往往会将图片存放在云服务器上

如 七牛云 等等。

  • 为了保护 客户的图片资源,图片云服务器 会在图片Url地址的基础上再加一个token参数
http://url.com/image.jpg?token=a6cvva6b02c670b0a
  • Glide加载该图片时,会使用加了token参数的图片Url地址 作为
    id参数,从而生成 缓存Key

2. 问题

  • 作为身份认证的token参数可能会发生变化,并不是一成不变
  • token参数变了,则图片Url跟着变,则生成缓存key的所需id参数发生变化,即 缓存Key也会跟着变化
  • 这导致同一张图片,但因为token参数变化,而导致缓存Key发生变化,从而使得 Glide的缓存功能失效

缓存Key发生变化,即同一个图片的当前缓存key 和 之前写入缓存的key不相同,这意味着 在读取缓存时 无法根据当前缓存key 找到之前的缓存,从而使得失效


3. 解决方案

3.1 原理

在 生成缓存Key 的id参数 前,将 带有token参数的图片Url地址 去掉 token参数,从而根据 初始的图片Url地址 生成缓存Key的id参数

实现了一个图片的缓存Key的id参数始终唯一 ,即等于 图片Url地址

3.2 储备知识:生成缓存Key的id参数的逻辑

生成缓存Keyid参数的逻辑为:直接将图片的 URL 地址作为缓存Key的id参数

回看文章:Android:手把手带你深入图片加载库Glide源码分析生成缓存Key的代码

public class Engine implements EngineJobListener,
        MemoryCache.ResourceRemovedListener,
        EngineResource.ResourceListener {

    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();

        final String id = fetcher.getId();
        // 获得了一个id字符串,即需加载图片的唯一标识
        // 如,若图片的来源是网络,那么该id = 这张图片的url地址
        // fetcher = HttpUrlFetcher的实例,即调用HttpUrlFetcher.getid()->>分析19

        EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),transcoder, loadProvider.getSourceEncoder());
        // 将该id 和 signature、width、height等10个参数一起传入到缓存Key的工厂方法里,最终创建出一个EngineKey对象
        // 创建原理:通过重写equals() 和 hashCode(),保证只有传入EngineKey的所有参数都相同情况下才认为是同一个EngineKey对象
       // 该EngineKey 即Glide中的缓存Key

        ...
}


<-- 分析19:getId() -->
public class HttpUrlFetcher implements DataFetcher<InputStream> {
    ...

    private final GlideUrl glideUrl;
    // GlideUrl = 在上篇文章讲解 图片加载 第2步load()中传入图片url地址时,Glide在内部把图片url地址包装成一个GlideUrl对象

    @Override
    public String getId() {
        return glideUrl.getCacheKey();
        // ->>分析20
}

<-- 分析20:getCacheKey()  -->

public class GlideUrl {

    private final URL url;
    private final String stringUrl;
    ...

    // GlideUrl构造函数
     public GlideUrl(URL url) {
        this(url, Headers.DEFAULT);
    }

    public GlideUrl(String url) {
        this(url, Headers.DEFAULT);
    }


    public String getCacheKey() {
        return stringUrl != null ? stringUrl : url.toString();
        // 在生成GlideUrl对象时:
        // 若传入的是URL字符串(即图片地址),就直接返回该字符串(大多数是这种情况)
        // 若传入的是URL对象,那么就返回这个对象toString()后的结果。

    }

    ...
}

3.3 实现方案

我们只需重写getCacheKey() & 将 带有token参数的图片Url地址 去掉 token参数 即可。

/**
  * 代码实现:创建一个GlideUrl类的子类 & 重写getCacheKey()
  **/
    // 1. 继承GlideUrl 
    public class mGlideUrl extends GlideUrl {

        private String mUrl;

        // 构造函数里 传入 带有token参数的图片Url地址 
        public MyGlideUrl(String url) {
            super(url);
            mUrl = url;
        }

        // 2. 重写getCacheKey()
        @Override
        public String getCacheKey() {
            return mUrl.replace(deleteToken(), "");
            // 通过 deleteToken() 从 带有token参数的图片Url地址中 去掉 token参数
            // 最终返回一个没有token参数、初始的图片URL地址
            // ->>分析1
        }

        // 分析1:deleteToken()
        private String deleteToken() {
            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;
        }

    }

/**
  * 使用缓存时:需要在load()中传入自定义的 mGlideUrl对象
  **/

    Glide.with(this)
         .load(new mGlideUrl(url))
         .into(imageView);

    // 注:a. 若像之前直接传入图片的url地址,那么在内部还是会使用原始的GlideUrl类
    //    b. 即直接将传入传入图片的url地址作为缓存key的Id参数,而没有对token参数作任何处理


4. 总结

本文主要对Glide的图片缓存功能的使用问题进行讲解

Carson带你学Android开源库系列文章:
Carson带你学Android:主流开源图片加载库对比(UIL、Picasso、Glide、Fresco)
Carson带你学Android:主流开源网络请求库对比(Volley、OkHttp、Retrofit)
Carson带你学Android:网络请求库Retrofit使用教程
Carson带你学Android:网络请求库Retrofit源码分析
Carson带你学Android:图片加载库Glide使用教程
Carson带你学Android:图片加载库Glide源码分析
Carson带你学Android:V-Layout,淘宝、天猫都在用的UI框架,赶紧用起来吧!


欢迎关注Carson_Ho的简书

不定期分享关于安卓开发的干货,追求短、平、快,但却不缺深度


请点赞!因为你的鼓励是我写作的最大动力!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容