Android-Glide的缓存机制

Android-Glide的缓存机制,第1张

很多小伙伴都在使用 Glide 加载图片,出去面试的时候肯定会被问起,“Glide缓存机制,你了解多少?”。这篇博客我来说说我了解到的 Glide 的缓存机制。

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

1.活动资源 (Active Resources) - 现在是否有另一个 View 正在展示这张图片?

2.内存缓存 (Memory cache) - 该图片是否最近被加载过并仍存在于内存中?

3.资源类型(Resource) - 该图片是否之前曾被解码、转换并写入过磁盘缓存?

4.数据来源 (Data) - 构建这个图片的资源是否之前曾被写入过文件缓存?

设置内存缓存开关:

设置磁盘缓存模式:

可以设置4种模式:

Glide四级缓存:

先找内存,再找文件

1)活动缓存(活动资源):ActiveResource,里边使用一个弱引用weakHashMap来保存正在使用的图片,当我们加载图片的时候,先从activeResource里边去查找,如果找不到的话就从内存缓存里查找。理论上没有大小限制,但是因为是弱引用管理的,所以是可回收的。 存活于内存当中,非持久化

2)内存缓存:默认使用的是LRU的memoryCache,如果没有找到,将从文件缓存中查找。 存活于内存当中,非持久化。

3)文件缓存:先从资源类型文件里查找(经过了圆角缩放处理的),然后从数据来源文件(未经过处理)里查找, 存活于磁盘中,持久化

这种框架的基本思路:源码的三条主线

(1)请求是怎样发送的?

(2)请求是怎样处理的?

(3)请求是怎样维护的?

Glide.with(context)  ---->构建一个RequestManager

.load()  ------------->输入数据模型,创建一个RequestBuilder,建造者模式

.into()------->调用RequestBuilder的load方法,buildRequest方法,传入target,

阅读本文需要先了解 Glide加载流程

首先介绍一下Glide中对图片资源的封装类: EngineResource

在活动缓存中,使用了一个map用来存放EngineResource对象,这里需要注意一个 *** 作,就是这个EngineResource对象是用WeakReference包裹的,并且通过ReferenceQueue监听了EngineResource的回收,在回收的时候会清理当前的活动缓存内容;

下面分析一下源码是如果实现的:

首先,自定义一个WeakReference类,将key和resource传进入(用于在WeakReference回收的时候释放),传入一个ReferenceQueue对象,用于监听WeakReference回收

开启一个子线程,在循环中监听ReferenceQueue的返回值,通过这个返回值,判断WeakReference有没有回收,监听的方法是ReferenceQueue.remove(),这是一个阻塞方法;所以要开子线程;

LruResourceCache继承了LruCache类,关于LruCache类,简单提一下,具体的可以参考我之前的博客 LruCache实现 ,LruCache继承了LinkedHashMap,LinkedHashMap有一个特点,就get后的数据会移动到队列,这就是Lru思想:固定一个容量,put的时候如果超过容量了,将最后一个节点删除,get的时候将get的这个节点移动到队列的头部;

onItemEvicted()方法是LruCache的一个空方法,调用的时机是在put的时候判断是否超过容量,如果超过容量了,就淘汰最后一个节点,并调用这个方法;

活动缓存和内存缓存都是缓存在内存中的,活动缓存缓存的是正在使用的图片资源,当图片不使用时会放到内存缓存中,提出活动缓存的目的:单一的内存缓存由于Lru的淘汰机制会导致图片加载不稳定

首先介绍一个磁盘缓存方案DiskLruCache(非Google官方编写,但获得官方认证),关于这个磁盘缓存方案的理解可以看郭林的这片文章:

Android DiskLruCache完全解析,硬盘缓存的最佳方案

从上一篇文章知道,Glide加载 *** 作是通过 Engine 来驱动的

Engine的load()中,首先尝试从 活动缓存 和 内存缓存 获取缓存,如果没有缓存再启动EngineJob和DecodeJob; 上面介绍了缓存的获取,下面看一下缓存的存放,肯定是在获取到图片后的回调中存放的

在DecodeJob获取到图片数据后,会回调很多接口,在回调中会将其放入 活动缓存 ,当图片不在使用的时候,就会放入内存缓存,根据上面介绍的活动缓存规则,当 EngineResource 计数为0时就应该放入内存缓存;

当资源引用为0,回调onResourceReleased(),从活动缓存移除,放入内存缓存;

上面介绍了活动缓存和内存缓存的存放和获取,下面看一看磁盘缓存的存取;

还记得 DataFetcherGenerator 接口吗?这个接口是DecodeJob用于获取数据的,有三个具体的实现:

我们在上一篇具体介绍的是网络文件的获取,这里的磁盘缓存使用的就是 DataCacheGenerator(缓存文件) 这个Generator了

上篇文章知道DecodeJob是一个Runnable任务,在run()会调用runWrapped(),在runWrapped()中会做三种事情:

在runWrapped()的解码 *** 作中会执行decode(),在decode()中,会disk put *** 作

Glide的磁盘缓存是基于DiskLruCache 实现的,Glide直接使用的是DiskLruCacheWrapper对象对DiskLruCache 的封装;


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/11008711.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-12
下一篇 2023-05-12

发表评论

登录后才能评论

评论列表(0条)

保存