扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
Glide库是用来实现图片加载的框架,功能强大且易使用,深受大家喜爱。
创新互联建站自2013年起,先为繁峙等服务建站,繁峙等地企业,进行企业商务咨询服务。为繁峙企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。
为啥要做缓存? android默认给每个应用只分配16M的内存,所以如果加载过多的图片,为了 防止内存溢出 ,应该将图片缓存起来。
图片的三级缓存分别是:
1、内存缓存
2、本地缓存
3、网络缓存
其中,内存缓存应优先加载,它速度最快;本地缓存次优先加载,它速度也快;网络缓存不应该优先加载,它走网络,速度慢且耗流量。
最优-优先级:内存缓存 本地缓存 网络缓存
两个方法实现:根据图片的url去加载图片、在本地和内存中缓存
两个方法实现:设置本地缓存,以及获取本地缓存
两个方法实现:设置内存缓存,获取内存缓存。
如果使用hashmap去存储图片时,当图片越来越多,那么会造成内存溢出,因为是强引用(对于强引用的系统不会回收)
如果改成软引用softReference,在android 2.3 以上的系统,对象会被提前回收。
可以用LruCache来解决上述内存不回收或提前回收的问题。least recentlly use 最少最近使用算法 它会将内存控制在一定的大小内, 超出最大值时会自动回收, 这个最大值开发者自己定。(这个东西没有用过..)
参考链接:
网络加载,不优先加载,速度慢,浪费流量
本地缓存,次优先加载,速度快
内存缓存,优先加载,速度最快
首次加载Android App时,肯定要通过网络交互来获取图片,之后我们可以将图片保存至本地SD卡和内存中,之后运行APP时,优先访问内存中的图片缓存,若内存中没有,则加载本地SD卡中图片,最后选择访问网络。
很多小伙伴都在使用 Glide 加载图片,出去面试的时候肯定会被问起,“Glide缓存机制,你了解多少?”。这篇博客我来说说我了解到的 Glide 的缓存机制。
默认情况下,Glide 会在开始一个新的图片请求之前检查以下多级的缓存:
1.活动资源 (Active Resources) - 现在是否有另一个 View 正在展示这张图片?
2.内存缓存 (Memory cache) - 该图片是否最近被加载过并仍存在于内存中?
3.资源类型(Resource) - 该图片是否之前曾被解码、转换并写入过磁盘缓存?
4.数据来源 (Data) - 构建这个图片的资源是否之前曾被写入过文件缓存?
设置内存缓存开关:
设置磁盘缓存模式:
可以设置4种模式:
本文源码解析基于Glide 4.6.1
系列文章
Android 【手撕Glide】--Glide缓存机制
Android 【手撕Glide】--Glide缓存机制(面试)
Android 【手撕Glide】--Glide是如何关联生命周期的?
Glide缓存分为内存缓存和磁盘缓存,其中内存缓存是由弱引用+LruCache组成。
取的顺序是:弱引用、LruCache、磁盘
存的顺序是:磁盘、弱引用、LruCache
这张亲手制作的图片,方便大家更直观的理解缓存机制的整体流程,结合文末总结效果更佳。喜欢的记得点赞!
概述
1、弱引用是由这样一个HashMap维护,key是缓存的key,这个key由图片url、width、height等10来个参数组成;value是图片资源对象的弱引用形式。
2、LruCache是由一个LinkedHashMap维护,根据Lru算法来管理图片。大致的原理是利用linkHashMap链表的特性,把最近使用过的文件插入到列表头部,没使用的图片放在尾部;然后当图片大小到达预先设置的一个阀值的时候 ,按算法删除列表尾部的部分数据。由于篇幅有限,这里不讲解LruCache和DiskLruCache的底层原理,这里推荐一篇 图解LinkedHashMap原理
这是Glide自定义的LruCache
存取原理
取数据
在内存缓存中有一个概念叫图片引用计数器 ,具体来说是在 EngineResource 中定义一个 acquired 变量用来记录图片被引用的次数,调用 acquire() 方法会让变量加1,调用 release() 方法会让变量减1。
获取图片资源是先从弱引用取缓存,拿到的话,引用计数+1;没有的话从LruCache中拿缓存,拿到的话,引用计数也是+1,同时把图片从LruCache缓存转移到弱应用缓存池中;再没有的话就通过 EngineJob 开启线程池去加载图片,拿到的话,引用计数也是+1,会把图片放到弱引用。
存数据
很明显,这是加载图片之后的事情。通过 EngineJob 开启线程池去加载图片,取到数据之后,会回调到主线程,把图片存到弱引用。当图片不再使用的时候,比如说暂停请求或者加载完毕或者清除资源时,就会将其从弱引用中转移到 LruCache 缓存池中。 总结一下,就是正在使用中的图片使用 弱引用 来进行缓存,暂时不用的图片使用 LruCache 来进行缓存的功能;同一张图片只会出现在 弱引用 和 LruCache 中的一个。
为什么要引入软引用?
1、分压策略,减少Lrucache 中 trimToSize 的概率。如果正在remove的是张大图,lrucache正好处在临界点,此时remove操作,将延缓Lrucache的 trimToSize 操作;
2 提高效率:弱引用用的是 HashMap ,Lrucache用的是 LinkedHashMap ,从访问效率而言,肯定是 HashMap 更高。
Glide磁盘缓存策略(4.x)
如果在内存缓存中没获取到数据会通过 EngineJob 开启线程池去加载图片,这里有2个关键类: DecodeJob 和 EngineJob 。 EngineJob 内部维护了线程池,用来管理资源加载,当资源加载完毕的时候通知回调; DecodeJob 是线程池中的一个任务。
磁盘缓存是通过 DiskLruCache 来管理的,根据缓存策略,会有2种类型的图片, DATA (原始图片)和 RESOURCE (转换后的图片)。磁盘缓存依次通过 ResourcesCacheGenerator 、 SourceGenerator 、 DataCacheGenerator 来获取缓存数据。 ResourcesCacheGenerator 获取的是转换过的缓存数据; SourceGenerator 获取的是未经转换的原始的缓存数据; DataCacheGenerator 是通过网络获取图片数据再按照按照缓存策略的不同去缓存不同的图片到磁盘上。
Glide缓存分为 弱引用+ LruCache+ DiskLruCache ,其中读取数据的顺序是:弱引用 LruCache DiskLruCache网络;写入缓存的顺序是:网络 -- DiskLruCache-- LruCache--弱引用
内存缓存分为弱引用的和 LruCache ,其中正在使用的图片使用弱引用缓存,暂时不使用的图片用 LruCache缓存,这一点是通过 图片引用计数器(acquired变量)来实现的,详情可以看内存缓存的小结。
磁盘缓存就是通过DiskLruCache实现的,根据缓存策略的不同会获取到不同类型的缓存图片。它的逻辑是:先从转换后的缓存中取;没有的话再从原始的(没有转换过的)缓存中拿数据;再没有的话就从网络加载图片数据,获取到数据之后,再依次缓存到磁盘和弱引用。
参考:
面试官:简历上最好不要写Glide,不是问源码那么简单
原来面试的时候写精通Glide,这样问我这样答
Android的Glide在加载图片时候内部默认使用了缓存机制,Glide的缓存机制分为两级,第一级是内存缓存,然后第二级是硬盘缓存。缓存的过程首先是在内存中缓存,然后将加载的图片资源缓存到硬盘,这样就可以在随后的再次加载中使用缓存了,Glide使用缓存时候首先要检查内存这一层级是否缓存了相应的缓存,如果有,则直接使用,如果没有,则深入到硬盘缓存中检查是否有,如果有,则加载之,如果到这一步骤还没有,那么就只能作为一个全新的资源加载了。
有些特定软件会在缓存图片文件夹自动生成名为“.nomedia”的文件,屏蔽了其他软件的扫描。代表此文件夹里面的MP3、MP4、RMVB、JPEG等图片音频视频等媒体文件,所以系统图库看不到。但一些特殊软件如 快图、MX Player也可以在设置中取消辨认这些文件!
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流