Glide源码流程分析

手写图片加载Glide框架demo

探索 Glide 原理

Glide使用必须知道的基础属性

Carson带你学Android:主流开源图片加载库对比(UIL、Picasso、Glide、Fresco)

Glide和picasso使用及区别

Glide三级缓存理解详细

Glide两个重要点:

  1. 缓存机制 (内存缓存 / 活动缓存 / LRU 磁盘缓存)
    1)活动缓存:在某个Activity范围,页面退出该缓存就不存在
    2)内存缓存:某个App范围,应用完全退出就不存在
    3)磁盘缓存:整个系统,只要不删除数据,就一直存在
  2. 生命周期(作用域是非Application(主线程中使用) 会添加一个空白Fragment,作用域是Application(子线程中使用) 不会添加一个空白的Fragment(跟随App的关闭而销毁))
    空白Fragment:
    android.app(v4) --> RequestManagerFragment
    androidx --> SupportRequestManagerFragment

创建Fragment 的原因
因为glide无法直接获取activity的生命周期,通过activity的FragmentManager中加入一个隐藏的fragment,因为fragment与传入的activity生命周期一致,所以只要监听这个RequestManagerFragment就能实现生命周期管理

图片加载流程:
① 先从活动缓存(非LRU算法,正在显示的图片)进行获取,找到里面显示;
② 如果活动缓存中找不到,再从LRU内存缓存中进行获取,如果找到,将LRU内存缓存移动到活动缓存,进行显示;

活动缓存和LRU内存缓存都是运行时缓存,如果把app杀掉,这两个缓存就不会存在,但是磁盘缓存会存在。
活动缓存与LRU内存缓存是互斥的,是移动操作(即两个缓存里面只能有一个缓存里面有);而活动缓存与磁盘缓存 资源不是互斥的,不是移动剪切操作是复制操作(两个缓存里面都可以有)。

③ 如果内存缓存找不到,就去LRU磁盘缓存(持久缓存)进行查找,如果找到,就从磁盘缓存中复制一份到活动缓存进行显示;
④ 如果LRU磁盘缓存找不到,就通过访问外置HTTP进行网络加载或者读取IO流,如果从外置HTTP加载或IO流能够加载成功,就把加载的数据保存到LRU磁盘缓存。

1. 时序图
在这里插入图片描述

2. 时序图中一些关键步骤中的解析说明:

Glide.with 将当前显示的页面对象传入Glide
SupportRequestManagerFragment 空的fragment 监听当前页面的生命周期
ActivityFragmentLifecycle 观察者模式,fragment的生命周期交给了他

Request previous = target.getRequest();
if(previous != null) {
判断当前的ImageView是否存在了请求
如果存在 将请求取消
并且回收资源
    previous.clear();
    this.requestTracker.removeRequest(previous);
    previous.recycle();
}

New BitmapRequest 创建请求 request是一个接口

Request request = this.buildRequest(target);
开始执行请求
this.requestTracker.runRequest(request);

请求的实现类

GenericRequest

Begin开始请求
DataFetcher 加载器 是一个接口
返回的子类型 是根据第一个参数 model 来确定

DataFetcher dataFetcher = modelLoader.getResourceFetcher(this.model, width, height);
this.loadStatus = this.engine.load(this.signature, width, height, dataFetcher, this.loadProvider, this.transformation, transcoder, this.priority, this.isMemoryCacheable, this.diskCacheStrategy, this);
把请求丢给图像处理引擎 处理图片

判断内存是否缓存了这张图片

EngineResource cached = this.loadFromCache(key, isMemoryCacheable);

负责加载每一个请求,它里面有线程池成员变量

EngineJob

实现Runable接口,具体执行请求逻辑 run()
功能:请求资源,处理资源,缓存资源

EngineRunnable

解析图片,返回glide里面的resource对象

resource = this.decode();

专门解析图片

decodeJob
通过加载器 实现图片加载   它是运行子线程  run方法被调用
加载网络图片时  data是inputStream类型
Object data = this.fetcher.loadData(this.priority);

解析Urlconnection返回的InputStream流对象

StreamBitmapDecoder

3. 流程图
4. Glide
开始
请求加载图片
创建RequestManager
通过buildRequest方法新建Request
当前页面是否暂停 isPaused
未暂停
执行Request  request.begin
判断内存缓存是否存在请求的图片
有
分发Bitmap
没有
创建EnginRunable线程
请求网络图片
处理图片
分发请求结果
暂停
不执行请求

=========================
问题1:
Glide不能在子线程中with?
答:子线程不会去添加生命周期机制,主线程才会来个 空白的Fragment 监听Activity/Fragment的变化
with()–>最终返回RequestManager对象
load()–>最终返回RequestBuilder对象
into()–>最终调用ImageViewTarget子类DrawableImageViewTarget的setResource()方法加载图片

@Override
protected void setResource(@Nullable Drawable resource) {
	view.setImageDrawable(resource);
}

问题2:为什么设置了内存缓存还要设置活动缓存呢?
答:内存缓存也叫LRU缓存 / 二级缓存
活动缓存也就是活动资源 / 活跃缓存 / 前台缓存
假如只有内存缓存,并且该设置缓存的maxSize=3,界面显示的imageView对应的资源正好是第一个位置的资源。现在要保存第4个资源到内存缓存中,根据LRU算法就会把最近最久未使用的资源移除掉,那么就会导致图片加载失败,从而导致应用崩溃。为了解决这样的问题,引入一个活动缓存,该缓存是非LRU缓存,用弱引用来存储数据。
imageView加载数据流程:
1)假如活动缓存中没有数据,就去访问内存缓存;
2)如果内存缓存中有数据,将内存缓存的数据移动到活动缓存,用于显示画面,内存缓存中的该资源会进行删除(这个地方注意,对应一个资源只能在内存缓存和活动缓存中一个,它们是互斥的)
3)假如用户将activity关闭,此时将活动缓存中的数据移动到内存缓存中
4)假如用户打开该activity界面,加载imageView,查找该活动缓存没有该资源,就会去内存缓存中查找,查找到该资源将该资源移动到活动缓存中,将内存缓存中的该资源删除

问题3:项目中大量的使用了Glide,偶尔会出现内存溢出问题,请说说大概是什么原因?
答:尽量在with的时候,传入有生命周期的作用域(非Application作用域),尽量避免使用了Application作用域,因为Application作用域不会对页面绑定生命周期机制,就回收不及时释放操作等…

问题4:使用Glide为什么要加入网络权限?
答:等待队列/运行队列 执行Request —> 活动缓存 —>内存缓存 —> jobs.get检测执行的任务有没有执行完成 —> HttpUrlFetcher.HttpURLConnection

问题5:使用Glide时,with函数传入Application后,Glide内部会怎么处理?
答:在MainActivity中,MainActivity销毁了,并会让Glide生命周期机制处理回收,只有在整个APP应用都没有的时候,跟随着销毁

总结:

  1. 安装app的加载流程
    第一次的时候,去网络下载图片,保存到磁盘缓存中
    第二次的时候,直接在活动缓存中,找到了资源
    第三次的时候,直接在活动缓存中,找到了资源
    … …
    第N次的时候,直接在活动缓存中,找到了资源

  2. 按home键,app退到后台
    把Activity给返回回去的时候,进行释放,活动缓存释放(活动缓存移动到内存缓存)
    又一次加载的时候,从内存缓存中获取了
    下一次加载的时候,就是从活动缓存获取了
    第二次的时候,直接在活动缓存中,找到了资源
    第三次的时候,直接在活动缓存中,找到了资源
    … …
    第N次的时候,直接在活动缓存中,找到了资源

  3. 杀掉app
    把App给杀掉,整个活动缓存、整个内存缓存都没有了(app消掉运行时都会被销毁),只有磁盘缓存
    首次冷启动,所以从磁盘缓存中获取
    第二次的时候,直接在活动缓存中,找到了资源
    第三次的时候,直接在活动缓存中,找到了资源
    … …
    第N次的时候,直接在活动缓存中,找到了资源

补充:
一、 普通的三级缓存:
1、内存缓存,优先加载,速度最快
2、本地缓存,次优先加载,速度快
3、网络缓存,最后加载,速度慢,浪费流量

三级缓存策略,最实在的意义就是减少不必要的流量消耗,增加加载速度。
普通的三级缓存对所有文件有适用,Glide三级缓存针对的是图片类型文件,其实对音频/视频文件也有参考价值,其他文件的缓存作用就不大了。

二、 Glide三级缓存分类:活动缓存、内存缓存、磁盘缓存,三级缓存范围:
1、活动缓存:在某个Activity范围,页面退出该缓存就不存在
2、内存缓存:某个App范围,应用完全退出就不存在
3、磁盘缓存:整个系统,只要不删除数据,就一直存在

图片缓存不会同时存在活动缓存和内存缓存。

三、三级缓存的作用:
1、活动缓存:分担内存缓存的负担,
2、内存缓存:加快数据读取
3、磁盘缓存:进行永久性保持

四、活动缓存的说明:
1、活动缓存并不是我们熟悉的内存缓存,是Glide自己定义的一种缓存策略。
2、本质上就是HasMap,用了一次就缓存,以后需要就直接拿,不需要就清除这个缓存。
3、该策略的存在也是为了及时释放内存,不需要等整个应用退出再释放内存,减轻应用内存负担。
4、活动缓存比内存缓存小,如果活动缓存满了,会自动写到内存缓存。
5、系统会对内存缓存进行自动管理,只要不是快速存放大内存文件,并且不一直占有内存对象,都不会内存溢出。

五、内存缓存的说明:
内存缓存是系统自身会管理的,但是可以继承LruCache,做进一步管理

六、磁盘缓存的说明:
1、磁盘缓存本质是本地文件缓存,但是通过普通的文件写入读取效率不高。
2、Glide中使用了DiskLruCache框架进行数据保存和读取。
3、效率高的主要原因是:磁盘缓存对图片文件进行了加密和压缩处理。

七、Glide三级缓存的使用
1、优先从活动缓存获取
2、活动缓存没有就再内存缓存中寻找
3、内存缓存没有,就去磁盘缓存读取
4、磁盘缓存没有就去网络获取本地文件读取

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值