Android Glide 里的缓存

Glide 里的缓存

默认情况下,Glide 会在开始一个新的图片请求之前检查多级缓存:

  • 1、活动资源(Activity Resource)- 现在是否有一个 View 正在展示这张图片?
  • 2、内存缓存(Memory cache)- 该图片是否最近被加载过并仍然存在内存中?
  • 3、资源类型(Resource)- 该图片是否之前曾被解码,转换并写入过磁盘缓存?
  • 4、数据来源(Data)- 构建这个图片的资源是否之前曾被写入过文件缓存?

前两步检查图片是否存在内存中,如果是则直接返回图片。后两步则检查图片是否在磁盘上,一遍快速异步的返回图片。
如果四个步骤都未能找到图片,则Glide会返回到原始资源以取回数据(原始文件,Uri, Url等)。
关于 Glide 缓存的默认大小与它们在磁盘上的位置的更多细节,或如何配置这些参数,请查看 配置 页面。

缓存键 (Cache Keys)

在 Glide v4 里,所有缓存键都包含至少两个元素:

  • 1、请求加载的 model(File, Uri, Url)。如果你使用自定义的 model, 它需要正确地实现 hashCode() 和 equals()
  • 2、一个可选的 签名(Signature)
    另外,步骤 1-3 (活动资源、内存缓存、资源磁盘缓存)的缓存键还包括一些其他的数据,包括:
  • 1、宽度和高度
  • 2、可选的变换(Transformation)
  • 3、额外添加的任何选项(Options)
  • 4、请求的数据类型(Bitmap,GIF或者其他)
    活动资源和内存缓存使用的键还和磁盘资源缓存略有不同,以适应内存 选项(Options),比如影响 Bitmap 配置的选项或其他解码时才会用到的参数。

为了生成磁盘缓存上的缓存键名称,以上的每个元素会被哈希化以创建一个单独的字符串键名,并在随后作为磁盘缓存上的文件名使用。

配置缓存

Glide 提供一系列的选项,以允许你选择加载请求与 Glide 缓存如何交互。

磁盘缓存策略(Disk Cache Strategy)

DiskCacheStrategy 可被 diskCacheStrategy 方法应用到每一个单独的请求。 目前支持的策略允许你阻止加载过程使用或写入磁盘缓存,选择性地仅缓存无修改的原生数据,或仅缓存变换过的缩略图,或是兼而有之。
默认的策略叫做 AUTOMATIC ,它会尝试对本地和远程图片使用最佳的策略。当你加载远程数据(比如,从URL下载)时,AUTOMATIC 策略仅会存储未被你的加载过程修改过(比如,变换,裁剪–译者注)的原始数据,因为下载远程数据相比调整磁盘上已经存在的数据要昂贵得多。对于本地数据,AUTOMATIC 策略则会仅存储变换过的缩略图,因为即使你需要再次生成另一个尺寸或类型的图片,取回原始数据也很容易。
指定 DiskCacheStrategy 非常容易:

Glide.with(fragment)
  .load(url)
  .diskCacheStrategy(DiskCacheStrategy.ALL)
  .into(imageView);

仅从缓存加载图片

某些情形下,你可能希望只要图片不在缓存中则加载直接失败(比如省流量模式)。如果要完成这个目标,你可以在单个请求的基础上使用 onlyRetrieveFromCache 方法:

Glide.with(fragment)
  .load(url)
  .onlyRetrieveFromCache(true)
  .into(imageView);

如果图片在内存缓存或在磁盘缓存中,它会被展示出来。否则只要这个选项被设置为 true ,这次加载会视同失败。

跳过缓存

如果你想确保一个特定的请求跳过磁盘和/或内存缓存(比如,图片验证码),Glide 也提供了一些替代方案。

仅跳过内存缓存,请使用 skipMemoryCache() :

Glide.with(fragment)
  .load(url)
  .skipMemoryCache(true)
  .into(view);

仅跳过磁盘缓存,请使用 DiskCacheStrategy.NONE :

Glide.with(fragment)
  .load(url)
  .diskCacheStrategy(DiskCacheStrategy.NONE)
  .into(view);

这两个选项可以同时使用:

Glide.with(fragment)
  .load(url)
  .diskCacheStrategy(DiskCacheStrategy.NONE)
  .skipMemoryCache(true)
  .into(view);

虽然提供了这些办法让你跳过缓存,但你通常应该不会想这么做。从缓存中加载一个图片,要比拉取-解码-转换成一张新图片的完整流程快得多。

如果你只是想更新缓存中的某个条目,请继续阅读下面关于 invalidation 介绍。

实现

如果内置的选项不满足你的需求,你也可以编写你自己的 DiskCache 实现。请查看 配置 页获得更多信息。

缓存的刷新

因为磁盘缓存使用的是哈希键,所以并没有一个比较好的方式来简单地删除某个特定 url 或文件路径对应的所有缓存文件。如果你只允许加载或缓存原始图片的话,问题可能会变得更简单,但因为 Glide 还会缓存缩略图和提供多种变换 (transformation),它们中的任何一个都会导致在缓存中创建一个新的文件,而要跟踪和删除一个图片的所有版本无疑是困难的。
在实践中,使缓存文件无效的最佳方式是在内容发生变化时(url,uri,文件路径等)更改你的标识符。

定制缓存的刷新策略

因为通常改变标识符比较困难或者根本不可能,所以Glide也提供了 签名 API 来混合(你可以控制的)额外数据到你的缓存键中。签名(signature)适用于媒体内容,也适用于你可以自行维护的一些版本元数据。

  • MediaStore 内容 - 对于媒体存储内容,你可以使用Glide的 MediaStoreSignature 类作为你的签名。MediaStoreSignature 允许你混入修改时间、MIME类型,以及item的方向到缓存键中。这三个属性能够可靠地捕获对图片的编辑和更新,这可以允许你缓存媒体存储的缩略图。
  • 文件 - 你可以使用 ObjectKey 来混入文件的修改日期。
  • Url - 尽管最好的让 url 失效的办法是让 server 保证在内容变更时对URL做出改变,你仍然可以使用 ObjectKey 来混入任意数据(比如版本号)。
    将签名传入加载请求很简单:
Glide.with(yourFragment)
    .load(yourFileDataModel)
    .signature(new ObjectKey(yourVersionMetadata))
    .into(yourImageView);

媒体存储签名对于 MediaStore 数据来说也很直接:

Glide.with(fragment)
    .load(mediaStoreUri)
    .signature(new MediaStoreSignature(mimeType, dateModified, orientation))
    .into(view);

你还可以定义你自己的签名,只要实现 Key 接口就好。请确保正确地实现 equals(), hashCode()updateDiskCacheKey() 方法:

public class IntegerVersionSignature implements Key {
    private int currentVersion;

    public IntegerVersionSignature(int currentVersion) {
         this.currentVersion = currentVersion;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof IntegerVersionSignature) {
            IntegerVersionSignature other = (IntegerVersionSignature) o;
            return currentVersion == other.currentVersion;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return currentVersion;
    }

    @Override
    public void updateDiskCacheKey(MessageDigest md) {
        messageDigest.update(ByteBuffer.allocate(Integer.SIZE).putInt(signature).array());
    }
}

请记住,为了避免降低性能,您将需要在后台批量加载任何版本元数据,以便在要加载图像时即已处于可用状态。

如果这些努力都无法奏效,您不能更改标识符,也不能跟踪任何合理的版本元数据的情况下,也可以使用 diskCacheStrategy()DiskCacheStrategy.NONE 来完全禁用磁盘缓存。

资源管理

Glide 的磁盘和内存缓存都是 LRU ,这意味着在达到使用限制或持续接近限制值之前,它们将占用持续增加的内存或磁盘空间。为了增加额外的灵活性,Glide 提供了一些额外的方式来让你可以管理你的应用使用的资源。
请记住,更大的内存缓存、位图池和磁盘缓存通常能提供更好的性能,或者至少在同等级别。如果你改变了缓存的大小, 你应该小心地测量一下你改动之前和之后的性能对比,以确保你的修改带来的性价比是可以接受的。

内存缓存

默认情况下 Glide 的内存缓存和 BitmapPool 会响应 ComponentCallback2 ,并根据 Android framework 提供的级别自动清理内容。 因此你通常不需要尝试动态监视或清理你的缓存或 BitmapPool。然而,如果必要的话,Glide 确实提供了几个手动选项。

永久尺寸调整

要改变你应用中 Glide 的可用 RAM 大小,请查看 配置

暂时尺寸

要在你应用的特定部分暂时允许 Glide 使用更多或更少的内存,你可以使用 setMemoryCategory:

// This method must be called on the main thread.
Glide.get(context).clearMemory();

清理所有内存并非特别经济,并且应该尽可能避免,以避免出现抖动和增加加载时间。

磁盘缓存

Glide 在运行时仅提供对磁盘缓存的有限控制,但是其大小和配置可以在 AppGlideModule 中改变。

永久尺寸修改

要改变你应用中 Glide 可用的 sdcard 可用空间,请查看 配置

清理磁盘缓存

要尝试清理所有磁盘缓存条目,你可以使用 clearDiskCache

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

推荐阅读更多精彩内容