Glide 的“三级缓存”通常指:
活动资源缓存 ActiveResources → 内存缓存 MemoryCache → 磁盘缓存 DiskCache
它的目的就是:同一张图片不要重复解码、重复下载,尽量快地显示出来,并减少内存和网络消耗。
一、Glide 三级缓存整体流程
假设你写了:
Glide.with(context)
.load(url)
.into(imageView)
Glide 大致会按这个顺序找图片:
1. ActiveResources 活动资源缓存
↓ 没有
2. MemoryCache 内存缓存
↓ 没有
3. DiskCache 磁盘缓存
↓ 没有
4. 网络 / 文件 / Uri 等原始数据源加载
也就是说:
先看当前正在用的图片有没有
再看内存里有没有
再看磁盘里有没有
最后才去网络下载
二、第一级:ActiveResources 活动资源缓存
1. 它是什么?
ActiveResources 可以理解为:
当前正在被页面使用、正在显示的图片资源。
例如:
imageView.setImageBitmap(bitmap)
这张图片此刻正在某个 ImageView 上显示,那么它就可能存在于 ActiveResources 中。
2. 为什么要有 ActiveResources?
假设一个列表中多个地方使用同一张图片:
ImageView A 显示 avatar.png
ImageView B 也显示 avatar.png
如果 A 已经在显示这张图片,B 再加载同一张图片时,Glide 可以直接从 ActiveResources 拿到,不用再去内存缓存或磁盘缓存找。
3. 特点
ActiveResources 的特点:
速度最快
不需要重新解码
图片正在被使用
一般通过弱引用/引用计数管理
它不是传统意义上“给你长期保存图片”的缓存,而是管理正在使用中的资源。
三、第二级:MemoryCache 内存缓存
1. 它是什么?
MemoryCache 是真正意义上的内存缓存,通常基于 LruCache 实现。
Lru 的意思是:
Least Recently Used,最近最少使用。
也就是说:
最近用过的图片留在内存里
很久没用的图片会被移除
2. 举个例子
比如你有一个 RecyclerView 图片列表。
你往下滑:
第 1 张图片离开屏幕
第 2 张图片离开屏幕
第 3 张图片离开屏幕
这些图片不再显示了,Glide 会尝试把它们从 ActiveResources 移到 MemoryCache。
如果你又往回滑:
第 1 张图片重新进入屏幕
Glide 就可以直接从内存缓存取出来,速度非常快。
3. MemoryCache 的优点
速度快
不需要重新读取磁盘
不需要重新网络下载
不需要重新完整解码
4. MemoryCache 的限制
内存缓存容量有限。
如果图片太多,Glide 不可能全部放在内存中,否则会 OOM。
所以它会按照 Lru 规则清理旧图片。
四、第三级:DiskCache 磁盘缓存
1. 它是什么?
DiskCache 是磁盘缓存,图片会被缓存到手机本地存储中。
相比内存缓存:
读取速度比内存慢
但是容量更大
App 进程被杀后仍然可能存在
可以避免重复网络下载
2. DiskCache 缓存的是什么?
Glide 的磁盘缓存主要可以分两类:
原始数据缓存 Data Cache
转换后资源缓存 Resource Cache
五、DiskCache 的两种缓存
1. Data Cache:原始数据缓存
比如你加载一张网络图片:
Glide.with(this)
.load("https://example.com/a.jpg")
.into(imageView)
Glide 从网络下载到的是原始图片数据,例如:
a.jpg 原图数据
这个就是 Data Cache。
它还没有经过:
缩放
裁剪
圆角
模糊
centerCrop
transform
2. Resource Cache:处理后资源缓存
如果你这样写:
Glide.with(this)
.load(url)
.centerCrop()
.override(200, 200)
.into(imageView)
Glide 最终显示的不是原图,而是经过处理后的图片:
原图 → 解码 → 缩放成 200x200 → centerCrop → 显示
这个处理后的结果就可以缓存为 Resource Cache。
下次再加载同样尺寸、同样变换的图片时,Glide 可以直接从 Resource Cache 里拿,不用重新解码和裁剪。
六、完整加载流程
可以把 Glide 的加载流程理解成这样:
开始加载图片
↓
查 ActiveResources
↓ 如果有,直接显示
没有
↓
查 MemoryCache
↓ 如果有,移到 ActiveResources,然后显示
没有
↓
查 Resource Disk Cache
↓ 如果有,读取处理后的图片,放入内存,然后显示
没有
↓
查 Data Disk Cache
↓ 如果有,读取原始图片数据,解码、变换、放入内存,然后显示
没有
↓
从网络 / 文件 / Uri 等数据源加载
↓
缓存到磁盘
↓
解码、变换
↓
放入内存
↓
显示到 ImageView
七、用一张图表示
Glide.with().load().into()
↓
┌──────────────────────┐
│ 1. ActiveResources │ 正在使用的资源
└──────────────────────┘
↓ miss
┌──────────────────────┐
│ 2. MemoryCache │ 内存 LruCache
└──────────────────────┘
↓ miss
┌──────────────────────┐
│ 3. DiskCache │ 磁盘缓存
│ - Resource Cache │ 处理后的图片
│ - Data Cache │ 原始图片数据
└──────────────────────┘
↓ miss
┌──────────────────────┐
│ 4. Source │ 网络、文件、Uri、资源等
└──────────────────────┘
八、ActiveResources 和 MemoryCache 的区别
很多人容易混淆这两个。
ActiveResources
正在使用中的图片
比如当前 ImageView 正在显示
优先级最高
速度最快
MemoryCache
暂时不用但还留在内存里的图片
比如 RecyclerView 滑出屏幕后缓存起来
方便下次快速复用
举个例子:
图片正在屏幕上显示:
ActiveResources
图片滑出屏幕,但还没被清理:
MemoryCache
图片 App 重启后还想复用:
DiskCache
九、Glide 缓存 Key 是什么?
Glide 判断“两次请求是不是同一张图片”,不是只看 URL。
它会根据一系列条件生成缓存 Key,例如:
图片 URL / 文件路径
图片尺寸 override(width, height)
图片变换 centerCrop、circleCrop、roundedCorners
签名 signature
资源类型 Bitmap / Drawable / Gif
Options 参数
所以:
Glide.with(this)
.load(url)
.override(100, 100)
.into(imageView1)
和:
Glide.with(this)
.load(url)
.override(300, 300)
.into(imageView2)
虽然 URL 一样,但尺寸不同,缓存 Key 可能不同。
十、常用缓存控制 API
1. 跳过内存缓存
Glide.with(this)
.load(url)
.skipMemoryCache(true)
.into(imageView)
意思是:
不放入内存缓存
但不代表不使用磁盘缓存
注意:一般不建议随便关内存缓存。
2. 设置磁盘缓存策略
Glide.with(this)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView)
常见策略:
DiskCacheStrategy.ALL
缓存原始数据和处理后的资源。
DiskCacheStrategy.DATA
只缓存原始数据。
DiskCacheStrategy.RESOURCE
只缓存处理后的资源。
DiskCacheStrategy.NONE
不使用磁盘缓存。
DiskCacheStrategy.AUTOMATIC
默认策略,Glide 自动判断。
十一、DiskCacheStrategy 怎么选?
1. 普通网络图片
一般直接用默认即可:
Glide.with(this)
.load(url)
.into(imageView)
Glide 默认会选择合适的缓存策略。
2. 如果想最大程度缓存
Glide.with(this)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView)
适合图片不经常变、希望二次加载很快的场景。
3. 如果图片经常变化但 URL 不变
比如头像 URL 不变,但图片内容变了。
可以加 signature:
Glide.with(this)
.load(url)
.signature(ObjectKey(version))
.into(imageView)
例如:
Glide.with(this)
.load(avatarUrl)
.signature(ObjectKey(userAvatarUpdateTime))
.into(imageView)
当 userAvatarUpdateTime 变化时,Glide 会认为这是新图片,重新加载。
十二、清除缓存
1. 清除内存缓存
必须在主线程调用:
Glide.get(context).clearMemory()
2. 清除磁盘缓存
必须在子线程调用:
Thread {
Glide.get(context).clearDiskCache()
}.start()
十三、一句话总结
Glide 的三级缓存是:
ActiveResources:当前正在显示的图片,最快
MemoryCache:内存中的 Lru 缓存,滑动列表时复用
DiskCache:磁盘缓存,避免重复下载和重复处理
加载顺序是:
ActiveResources → MemoryCache → DiskCache → 网络/文件源
其中磁盘缓存又分为:
Resource Cache:处理后的图片
Data Cache:原始图片数据