本文主要介绍了如何配置和管理 Glide 中的缓存,其中大部分内容都可以直接在官方 Wiki 中找到,这里只是进行了整理和汇总。言归正传,Glide 支持图片的二级缓存(并不是三级缓存,因为从网络加载并不属于缓存),即内存缓存和磁盘缓存。
磁盘缓存
一般的图片缓存指的就是磁盘缓存,把网络上的图片缓存到本地,这样就不需要每次都从网络加载,既提高了加载速度,又为用户节省了流量。Glide 在默认情况下是开启磁盘缓存的,而且提供了丰富的 API 来让开发者自己配置和管理磁盘缓存。
缓存位置和大小
开发者可以通过构建一个自定义的GlideModule来配置 Glide 磁盘缓存的位置和大小。最简单的方法如下:
1 | public class DiskCacheMoudle implements GlideModule { |
其中 InternalCache 和 ExternalCache 都最多接收 3 个参数:第一个参数为 Context,没啥好说的;第二个为缓存的目录名称;第三个为缓存大小,单位是 Byte。它们之间唯一的不同就在于 InternalCache 构建的缓存是在应用的内部储存,而 ExternalCache 则是在外部储存。内部储存中的缓存文件是其他应用程序是无法获取到的,更加安全。关于内部储存和外部储存的更多内容,请点击这里查看官方文档。
如果不想把缓存放在上面的两个位置怎么办?Glide 当然也支持,具体通过 DiskLruCacheFactory 来实现:
1 | builder.setDiskCache( |
Note: getMyCacheLocationBlockingIO 方法返回的文件不能为空,而且必须是一个已经创建好的文件目录,不可以是文件。
缓存策略
与其他图片加载库的缓存机制不同,Glide 缓存图片时默认只缓存最终加载的那张图片。举个栗子,你要加载的图片分辨率为 1000x1000,但是最终显示该图片的 ImageView 大小只有 500x500,那么 Glide 就会只缓存 500x500 的小图。这也是在从磁盘缓存中加载图片时 Glide 比 Picasso 快的原因。Glide 目前提供了四种缓存策略:
- DiskCacheStrategy.NONE 不缓存文件
- DiskCacheStrategy.SOURCE 只缓存原图
- DiskCacheStrategy.RESULT 只缓存最终加载的图(默认的缓存策略)
- DiskCacheStrategy.ALL 同时缓存原图和结果图
缓存算法
在 Glide 中磁盘缓存默认使用的是 LRU(Least Recently Used)算法。如果你想使用其他的缓存算法,就只能通过实现 DiskCache 接口来完成了。
内存缓存
使用内存缓存可以获得更快的图片加载速度,因为减少了耗时的 IO 操作。众所周知,Bitmap 是 Android 中的内存大户,频繁的创建和回收 Bitmap 必然会引起内存抖动。Glide 中有一个叫做 BitmapPool 的类,可以复用其中的 Bitmap 对象,从而避免 Bitmap 对象的创建,减小内存开销。当配置内存缓存时,我们也应该同时配置 BitmapPool 的大小。具体方法也是通过自定义的 GlideModule 来实现的:
1 | builder.setMemoryCache(new LruResourceCache(yourSizeInBytes)); |
一般情况下,开发者是不需要自己去指定它们的大小的,因为 Glide 已经帮我们做好了。默认的内存缓存和 bitmapPool 的大小由MemorySizeCalculator根据当前设备的屏幕大小和可用内存计算得到。同时 Glide 还支持动态的缓存大小调整,在存在大量图片的 Activity/Fragment 中,开发者可以通过 setMemoryCategory 方法来提高 Glide 的内存缓存大小,从而加快图片的加载速度。
1 | Glide.get(context).setMemoryCategory(MemoryCategory.HIGH); |
MemoryCategory 有 3 个值可供选择:
- MemoryCategory.HIGH(初始缓存大小的 1.5 倍)
- MemoryCategory.NORMAL(初始缓存大小的 1 倍)
- MemoryCategory.LOW(初始缓存大小的 0.5 倍)
在有些情况下我们不希望做内存缓存(比如加载 GIF 图片),这个时候可以调用 skipMemoryCache(true)方法跳过内存缓存。
如何缓存动态 Url 的图片
一般情况下我们从网络上获取到的图片 Url 都是静态的,即一张图片对应一个 Url。那么如果是一张图片对应多个 Url 呢?缓存不就没有意义了。因为图片加载库都是拿图片的 Url 来作为缓存的 key 的,Glide 也不例外,只是会更加复杂一些。如果你开启了 Glide 的 log,就会在控制台看到 Glide 是如何指定缓存 key 的。关于如何打开 log,请参考这篇文章。一般来说,Glide 的 key 由图片的 url、view 的宽和高、屏幕的尺寸大小和 signature 组成。
在什么情况下才会出现动态的 Url 呢?一个很典型的例子就是因为图片的安全问题在原来图片的 Url 后面加上访问凭证。访问凭证与时间关联,这样一来,在不同时间同一图片的 Url 就会不同,缓存就会失效。以七牛的私有空间为例,我们来看看如何去缓存这类图片。从七牛关于私有空间的文档中可以得到:最终的 Url = 原 Url + ?e=过期时间 + token=下载凭证。那么就只需要在 Glide 缓存时将 Url 中“?”后面的字符串截去就可以了。
首先新建一个叫做 QiNiuImage 的类:
1 | public class QiNiuImage { |
其中 getImageUrl 方法返回真实的 Url,getImageId 方法返回未添加下载凭证前的 Url。
然后再自定义一个实现ModelLoader接口的 QiNiuImageLoader:
1 | public class QiNiuImageLoader implements StreamModelLoader<QiNiuImage> { |
其中 HttpUrlFetcher 的 getId 方法就是组成缓存的 key 的重要部分。这也是我们的核心原理。
将这个 ModelLoader 注册到 GlideModule 中,并在 AndroidManifest.xml 中注册:
1 | public class QiNiuModule implements GlideModule { |
1 | <meta-data |
最后只需要在加载此类图片时,使用下面这段代码就可以了。即使图片的 token 更换了也不会重新从网络上下载而是直接读取本地缓存。
1 | Glide.with(context) |
参考资料: