Glide 三部曲之图片加载流程

  • 本文章所使用的 Glide 源码版本:4.11.0

上一篇:Glide 三部曲之请求生命周期管控

开胃菜

  • 上一篇我们讲到了 Glide 的生命周期管控是由 with 方法完成,那么加载过程是不是由 load 方法完成的呢?
  • 接下来让我们把目光放到 String 参数的 load 方法上
  • 再来看看 File 参数的 load 方法
  • 经过这两段代码的对比,我们基本可以断定 Glide.load 做的事情很简单,只是对加载的数据源进行封装,并没有进行加载操作

  • 其实真正的加载操作是放在 Glide.into 方法,刚刚只是开胃菜,接下来正式进入今天的主题:Glide.into

源码解析

  • 看到这里,我们可能对 buildImageViewTarget 方法很好奇,为什么不直接传入 ImageView,而是通过一个 Target 类把 ImageView 包起来了呢,Glide 为什么要这么做?接下来让我们回归 into 方法的源码
  • 看到这里我们基本可以猜到使用 Target 的主要作用,它是将网络请求和 ImageView 绑定在一起的那么一个类,如果这个 ImageView 已经有图片加载请求了,那么会先判断现在要进行的图片加载请求是否和上一次的图片加载请求是否是同一个,如果是的话,则复用之前的 Target 对象,如果不是的话则会将上一次的图片加载请求移除掉,再把新的图片加载请求设置给 Target 对象,然后交给 RequestManager 执行该请求

  • 那么问题来了,Target 对象是如何和 ImageView 对象绑定在一起的,还有 Glide 为什么要这么做?带着这两个问题我们接着看源码

  • 看完了这些代码,我们可以得出一个结论,图片加载请求是通过 ImageView.setTag 和 ImageView 绑定在一起的

  • 那 Glide 为什么要这么做呢?又或者说这样做的目的是什么?我们需要考虑一种情况,如果我们向同一个 ImageView 对象同时发送两次图片加载请求,那么哪一次会先加载完成呢?这个真的说不准,有可能是第一次,也有可能是第二次,因为图片加载请求是异步的,我们无法准确预料这一时机,在这两次请求中,如果我们不对原有的请求进行解绑,那么很可能导致图片显示错乱的情况发生,也就是我们希望先加载第一次请求的图片资源再加载第二次请求的图片资源,但是实际情况可能相反,如果在第一张图片资源的大小比第二张图片资源要大的时候,那么这种非正常情况就会大概率会发生,这种情况在 RecyclerView 和 ListView 复用中很常见,所以 Glide 采用了 ImageView 和请求相互绑定的方式来解决这一问题。

  • 讲完了这块的内容,我们接着讲 Glide 执行图片加载请求的过程

  • 一路跟踪源码到了这里,我们可以看到,Glide 会判断我们有没有指定图片的宽高参数,如果没有指定的话它会对 ImageView 的宽高进行计算
  • 看到这里,我们先回顾一下刚刚看过的一段源码
  • 我们可以看到,如果我们没有指定图片的宽高,target.getSize 方法最终也会回调到 onSizeReady 方法上,只不过它多了一个对 ImageView 宽高的计算,所以绕了一圈还是回到原来的地方上了

  • 接下来让我们继续追踪源码,看看它还干了什么事

  • 通过查看这段代码,Glide 会先读取内存中的缓存,如果已经存在缓存则会直接复用,如果没有的话则会进行加载。

  • 接下来让我们简单看看 Glide 对内存缓存是怎么做处理的

  • 通过分析这段源码,我们可以得出,Glide 会判断有没有指定跳过内存缓存,如果是的话直接返回 null,也就是要从磁盘或者网络上获取,如果不是的话,Glide 会从内存缓存中取,这里有一个地方需要我们注意,Glide 的内存缓存有两种,一种是正在使用的内存缓存,也就是显示在 ImageView 上面的图片资源,另一种是没有在 ImageView 上面显示但是之前有加载过的图片资源

  • 我们先来看看一级内存缓存的源码

  • 经过查看源码可以得出,一级内存缓存其实就是一个弱引用图片资源的集合

  • 接下来让我们看看二级内存缓存的源码

  • Glide 会从二级内存缓存中读取图片资源,如果这个资源不为空,会将这个图片资源从二级内存缓存中移除,然后转移到一级内存缓存中

  • 然后再来看看它是怎么实现二级内存缓存的

  • 在这里我们可以看到,二级内存缓存无非还是使用了 LruCache 来实现,值得一提的是这个 LruCache 类是 Glide 自定义的,可能和谷歌实现不太一样,但是其中的思想都是一样的,都是在内存缓存达到了设定的最大值,会将使用次数最少的缓存对象移除掉。

  • 说完了内存缓存,接下来再讲讲在没有内存缓存的情况下 Glide 会怎么做

  • 在这里我们看到了两个类,一个是 EngineJob,另一个是 DecodeJob,那么问题来了,这两个类是什么?有什么作用?
  • 从这两个类的注释我们可以看出这两个类的作用,EngineJob 负责管理加载回调的,而 DecodeJob 负责图片资源加载、解码、转换,所以这里我们重点讲一下 DecodeJob 类
  • 简单讲一下这三个方法的作用,getNextStage 方法会判断图片的缓存策略返回对应的枚举(缓存原图、缓存 ImageView 大小图片,没有缓存),然后 getNextGenerator 方法再根据不同的缓存策略返回不同的处理策略(读取原图,读取 ImageView 大小图片,从网络上读取),runGenerators 方法则是执行读取操作

  • 然后我们接着看它读取完图片资源之后做了什么事

  • 通过追踪源码得出结论,Glide 在没有内存缓存的情况下,会读取磁盘上或者网络上的缓存,读取完毕之后不会立即加载到 ImageView,而是先加入一级内存缓存中再进行加载

  • 接下来再看看它是怎么加载给 ImageView 对象的,我们先回退几步,然后接着追踪源码

  • 经过对源码的追踪,最终还是回到我们最初的 Target 类中,最终根据我们设定的类型给 ImageView 加载图片资源
  • Glide 整套加载流程的源码是极其复杂的,类和类之间的关系也是非常复杂,看着看着容易迷路

总结

  • Glide 加载图片之前它会先设置一个 Target 对象将图片加载请求和 ImageView 绑定在一起,由此保证一个 ImageView 只有一个图片加载请求并且是最新的,然后获取图片显示在 ImageView 上面的宽高,如果我们没有指定图片的宽高,则会对 ImageView 的宽高进行计算,接着会判断内存缓存中是否已经有图片缓存,它会从两个地方获取,先从正在显示的图片集合中查找,如果没有再从缓存池中查找,这两种方式分别是一级内存缓存和二级内存缓存,两者的区别是,一级内存缓存使用的是一个弱引用的集合来存储,而二级内存缓存使用的是 LruCache 算法来存储。如果内存缓存中没有,会判断图片资源是否有本地缓存,如果有的话直接从磁盘上面读取,如果没有的话会先从网络下载到磁盘上再进行读取,读取完资源后并不会立即加载到 ImageView 上,而是先把图片加载到一级内存缓存中,再通过 Target 类加载到绑定的 ImageView 上面。

下一篇:Glide 三部曲之 Gif 加载原理

Android 技术讨论 Q 群:10047167

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268