1、Glide的缓存
- Glide 在加载图片时会依次访问以下缓存:
- 活动资源 (Active Resources) - 现在是否有另一个 View 正在展示这张图片?
- 内存缓存 (Memory cache) - 该图片是否最近被加载过并仍存在于内存中?
- 资源类型(Resource) - 该图片是否之前曾被解码、转换并写入过磁盘缓存?
- 数据来源 (Data) - 构建这个图片的资源是否之前曾被写入过文件缓存?
上面的四个步骤就代表了Glide的缓存机制,当四步缓存中未查找对应的资源时再执行网络请求加载资源,加载完成后也会按照这四步缓存资源;
2、缓存策略
2.1、磁盘缓存
- DiskCacheStrategy: 设置Glide的缓存策略,通过设置缓存策略可选择性地控制缓存原数据还是缓存转换后的数据,或是二者都缓存
- 默认的策略叫做 AUTOMATIC,它会尝试对本地和远程图片使用最佳的策略
- AUTOMATIC : 当加载远程数据(比如,从URL下载)时,AUTOMATIC 策略仅会存储未被你的加载过程修改过(比如,变换,裁剪)的原始数据;
- AUTOMATIC : 对于加载本地数据,AUTOMATIC 策略则会仅存储变换过的缩略图,因为图片在本地比较容易直接获取;
- 修改指定的DiskCacheStrategy的缓存策略
GlideApp.with(fragment)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView);
Glide提供以下
- ALL : 缓存数据和资源的远程数据,以及仅用资源的本地数据。
- AUTOMATIC:默认的缓存策略
- DATA:在解码之前将检索到的数据直接写入磁盘缓存。
- NONE:不缓存
- RESOURCE:在解码后将资源写入磁盘。
2.2、 仅从缓存加载
GlideApp.with(fragment)
.load(url)
.onlyRetrieveFromCache(true)
.into(imageView);
当开启仅从缓存加载去加载数据,除非加载的图片已经在内存缓存或磁盘缓存中,否则加载失败;
2.3、跳过缓存
- skipMemoryCache():仅跳过内存缓存
GlideApp.with(fragment)
.load(url)
.skipMemoryCache(true)
.into(view);
- DiskCacheStrategy.NONE: 跳过磁盘缓存
.diskCacheStrategy(DiskCacheStrategy.NONE)
- 两者都跳过
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
3、配置缓存
Glide 允许应用通过 AppGlideModule 实现来配置 Glide 的内存和磁盘缓存使用,可以配置缓存文件的位置和缓存控件的大小
- 配置缓存位置
(3)磁盘缓存
Glide 使用 DiskLruCacheWrapper 作为默认的 磁盘缓存 , DiskLruCacheWrapper 是一个使用 LRU 算法的固定大小的磁盘缓存,默认磁盘大小为 250 MB ,位置在手机内存中应用的缓存文件夹 中的一个 特定目录
- 设置缓存存储位置
builder.setDiskCache(new ExternalDiskCacheFactory(context));
builder.setDiskCache(new ExternalPreferredCacheDiskCacheFactory(context));
Glide内置3中设置存储位置的Factory
- InternalCacheDiskCacheFactory:缓存在手机内存的缓存文件中
- ExternalDiskCacheFactory:设置缓存文件在外部存储中
- ExternalPreferredCacheDiskCacheFactory:如果之前存储在内部存储中,则会维持不变继续使用,否则使用外部缓存文件;
- 应用程序都可以改变磁盘缓存的大小
int diskCacheSizeBytes = 1024 1024 100; 100 MB
builder.setDiskCache(new InternalDiskCacheFactory(context, diskCacheSizeBytes));
- 应用程序还可以改变缓存文件夹在外存或内存上的名字:
int diskCacheSizeBytes = 1024 1024 100; 100 MB
builder.setDiskCache( new InternalDiskCacheFactory(context, cacheFolderName, diskCacheSizeBytes));
- 自定义 MemoryCache的大小,具体是在它们的 AppGlideModule 中使用applyOptions(Context, GlideBuilder) 方法配置 MemorySizeCalculator
@Override
public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
super.applyOptions(context, builder);
MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context) //Glide内部默认配置
.setMemoryCacheScreens(2)
.build();
builder.setMemoryCache(new LruResourceCache(calculator.getBitmapPoolSize()));
}
- 直接限定缓存的大小
int memoryCacheSizeBytes = 1024 * 1024 * 20;
builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));
3.1、Bitmap池
- Glide 使用 LruBitmapPool 作为默认的 BitmapPool
- 在 AppGlideModule 中定制 BitmapPool的尺寸,使用 applyOptions(Context, GlideBuilder) 方法并配置 MemorySizeCalculator:
@Override
public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
super.applyOptions(context, builder);
MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context)
.setMemoryCacheScreens(2)
.build();
builder.setBitmapPool(new LruBitmapPool(calculator.getBitmapPoolSize()));
}
- 直接限定大小
int bitmapPoolSizeBytes = 1024 * 1024 * 30; // 30mb
builder.setBitmapPool(new LruBitmapPool(bitmapPoolSizeBytes));
4、缓存的刷新
4.1、定制缓存刷新策略
Glide的内部缓存会根据多种条件创建最终缓存的Key,显然我们如果要刷新请求而不实用缓存就必须改变获取的键,使获取的和储存的键不一致,这样缓存失效就会加载新的数据,通常改变标识符比较困难或者根本不可能,所以Glide也提供了 签名 API 来混合额外数据到你的缓存键中,针对以下3种类型资源提供以下方案:
- MediaStore 内容 - 对于媒体存储内容,可以使用Glide的 MediaStoreSignature 类作为签名,MediaStoreSignature允许你混入修改时间、MIME类型,以及item的方向到缓存键中,这三个属性能够可靠地捕获对图片的编辑和更新,这可以允许缓存媒体存储的缩略图。
- 文件 - 使用 ObjectKey 来混入文件的修改日期,改变日期时即可刷新缓存
- Url - 针对Url有两种有限方法:1、让 server 保证在内容变更时对URL做出改变;2使用 ObjectKey 来混入任意数据来改变Url
例子:第一次加载,将缓存的键混入数字“123”:
GlideApp.with(this)
.load("http://img.zcool.cn/community/01638059302785a8012193a36096b8.jpg@2o.jpg")
.placeholder(R.mipmap.ic_launcher)
.error(R.drawable.ic_launcher_background)
.signature(new ObjectKey("123"))
.transition(new DrawableTransitionOptions().crossFade())
.into(imageView);
- 将手机断开网络重新进入程序,因为有缓存的存在所以可以直接加载图片,现在修改程序中键掺入的123为456:
.signature(new ObjectKey("456"))
- 此时网络为断开,且再次请求的键与之前缓存的并不相同,此时加载失败,连接网络后会重新拉取图片并缓存,图片加载成功
- 此时内存中是有两个缓存图片,分别对应两次请求所生成的键
- 也定义你自己的签名,只要实现 Key 接口就好,并重写其中的方法,还记得之前看过处理七牛云图片Url的文章就是自定义Key保证缓存有效
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());