本文源码解析基于Glide 4.6.1

系列文章
Android 【手撕Glide】--Glide缓存机制
Android 【手撕Glide】--Glide缓存机制(面试)
Android 【手撕Glide】--Glide是如何关联生命周期的?

引入缓存的目的

  • 1、减少流量消耗,加快响应速度;
  • 2、Bitmap 的创建/销毁比较耗内存,可能会导致频繁GC;使用缓存可以更加高效地加载 Bitmap,减少卡顿。

Glide缓存流程

Glide缓存分为内存缓存和磁盘缓存,其中内存缓存是由弱引用+LruCache组成。

取的顺序是:弱引用、LruCache、磁盘
存的顺序是:磁盘、弱引用、LruCache

这张亲手制作的图片,方便大家更直观的理解缓存机制的整体流程,结合文末总结效果更佳。喜欢的记得点赞!

Glide缓存机制.png

注意:关于缓存的存取的入口在Engine这个类中

内存缓存原理

概述

1、弱引用是由这样一个HashMap维护,key是缓存的key,这个key由图片url、width、height等10来个参数组成;value是图片资源对象的弱引用形式。

Map activeEngineResources = new HashMap<>();

2、LruCache是由一个LinkedHashMap维护,根据Lru算法来管理图片。大致的原理是利用linkHashMap链表的特性,把最近使用过的文件插入到列表头部,没使用的图片放在尾部;然后当图片大小到达预先设置的一个阀值的时候 ,按算法删除列表尾部的部分数据。由于篇幅有限,这里不讲解LruCache和DiskLruCache的底层原理,这里推荐一篇 图解LinkedHashMap原理

这是Glide自定义的LruCache

#LruCacheMap cache = new LinkedHashMap<>(100, 0.75f, true);

存取原理
取数据
在内存缓存中有一个概念叫图片引用计数器 ,具体来说是在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更高。

磁盘缓存原理(DiskLruCache)

Glide磁盘缓存策略(4.x)

  • DiskCacheStrategy.DATA: 只缓存原始图片;
  • DiskCacheStrategy.RESOURCE:只缓存转换过后的图片;
  • DiskCacheStrategy.ALL:既缓存原始图片,也缓存转换过后的图片;对于远程图片,缓存 DATA和 RESOURCE;对于本地图片,只缓存 RESOURCE;
  • DiskCacheStrategy.NONE:不缓存任何内容;
  • DiskCacheStrategy.AUTOMATIC:默认策略,尝试对本地和远程图片使用最佳的策略。当下载网络图片时,使用DATA(原因很简单,对本地图片的处理可比网络要容易得多);对于本地图片,使用RESOURCE

如果在内存缓存中没获取到数据会通过EngineJob开启线程池去加载图片,这里有2个关键类:DecodeJobEngineJobEngineJob 内部维护了线程池,用来管理资源加载,当资源加载完毕的时候通知回调; DecodeJob是线程池中的一个任务。

磁盘缓存是通过DiskLruCache来管理的,根据缓存策略,会有2种类型的图片,DATA(原始图片)和 RESOURCE(转换后的图片)。磁盘缓存依次通过ResourcesCacheGeneratorSourceGeneratorDataCacheGenerator来获取缓存数据。ResourcesCacheGenerator获取的是转换过的缓存数据;SourceGenerator获取的是未经转换的原始的缓存数据;DataCacheGenerator是通过网络获取图片数据再按照按照缓存策略的不同去缓存不同的图片到磁盘上。

总结(干货)

Glide缓存分为弱引用+ LruCache+ DiskLruCache,其中读取数据的顺序是:弱引用 > LruCache > DiskLruCache>网络;写入缓存的顺序是:网络 --> DiskLruCache--> LruCache-->弱引用

内存缓存分为弱引用的和 LruCache ,其中正在使用的图片使用弱引用缓存,暂时不使用的图片用 LruCache缓存,这一点是通过 图片引用计数器(acquired变量)来实现的,详情可以看内存缓存的小结。

磁盘缓存就是通过DiskLruCache实现的,根据缓存策略的不同会获取到不同类型的缓存图片。它的逻辑是:先从转换后的缓存中取;没有的话再从原始的(没有转换过的)缓存中拿数据;再没有的话就从网络加载图片数据,获取到数据之后,再依次缓存到磁盘和弱引用。

参考:
面试官:简历上最好不要写Glide,不是问源码那么简单
原来面试的时候写精通Glide,这样问我这样答

更多相关文章

  1. Android(安卓)性能优化之内存优化
  2. listview背景选择
  3. Android(安卓)Handler 异步消息处理机制的妙用 创建强大的图片加
  4. html5,移动端开发(1)
  5. Android(安卓)ListView滑动过程中图片显示重复错乱闪烁问题解决
  6. 【Android】OkHttp源码分析
  7. Android(安卓)开发环境配置 之后(释放你的C盘)
  8. Android(安卓)Handler 异步消息处理机制的妙用 创建强大的图片加
  9. Android(安卓)Opencv 之 Android(安卓)Studio 进行 opencv ( 4.2.

随机推荐

  1. Android(安卓)开发框架
  2. Android面试系列文章2018之Android部分Fr
  3. 组合android的theme属性
  4. Android(安卓)xml资源文件中@、@android:
  5. AndroidResource
  6. android 笔记 --- ImageView的属性androi
  7. 由Android想到的事情
  8. Android(安卓)资源文件中@、@android:typ
  9. Android(安卓)GridView属性
  10. android开发_文本按钮 与 输入框