Glide架构设计艺术

自从Android诞生以来,Bitmap的管理就一直是大问题,为了更好的管理它,不同的图片加载框架不断的被推出,从刚开始的ImageLoader,到Picasso,再到现在的Fresco和Glide,可谓百花齐放。然而前两者现在都已经不再维护了,同时我们公司的项目目前也已经从Fresco切换到Glide了,之前之所以用Fresco是因为他在Android5.0以下系统中能从native层“偷”内存,但后面由于Android对于Bitmap内存管理方式的改变,这个功能不再生效,相比于Glide来说,Fresco就显得侵入性太强,而且可扩展性没有glide强。而Glide之所以扩展性如此强,就在于它 优秀的架构设计 ,这也是我们今天要讨论的。

1. 总体架构

首先我们看下Glide总体架构图:


glide总体架构图

从架构图上,我们可以看出,glide并没有着眼于bitmap,而是进行了高度的抽象,所以我们不应该将glide看成一个图片加载框架,而是一个资源从不同形态之间转换的框架,从url到bitmap只是其中一种,所以我们不难理解glide甚至能从视频加载第一帧,因为它没有对输入类型做任何限制,都是统一抽象成的Request。

2. 从Request到Data的设计——资源加载模块设计

首先我们看下总体过程:


glide从Request到Data.png

这里以从url到inputstream二进制流为例,之所以这里有三条分路,这和glide的缓存策略有关。首先有一点要澄清,这里从Request到Data其实是跳过了内存缓存的介绍,毕竟如果内存中已有bitmap缓存,我们直接取用就可以了,无需这么麻烦(详细的缓存方案后续文章会介绍)。因此,这里有三条路径主要是磁盘缓存和网络缓存,而磁盘缓存有两种:

  • DataCache 从原始Request加载到的二进制流直接缓存,比如从url加载的原图缓存
  • ResourceCache 将从Request获取的Data数据处理后缓存,比如将一个url的原图进行压缩后又缓存起来,glide能够缓存不同尺寸的图片的原因就在于这一步。
    而SourceGenerator就是跳过缓存直接从原始Request获取请求了。

2.1 Request是如何被加载的

由于glide的这种高度抽象,现在我们面临着一个问题:如此多类型的Request和如此多的Data,具体怎么去加载它呢?比如说Request有url、uri、File、资源id、视频等等,不同的Request肯定有不同的加载方式,同一个Request既可能从网络加载,也可能从磁盘加载,可能性太多,那么我们怎么去加载呢?if-else去判断吗? 一个优秀的框架肯定不会干这种low到爆的事。这里我们介绍一些新的角色:


ModelLoader类图.png

这里,针对每一种Request,我们都有对应的ModelLoader,当一个Request进来时,我们可以遍历所有的ModelLoader,通过handles()方法判断这个ModelLoader能否处理这种Request,这样我们就能解决第一个问题,即不同的Request如何管理加载,有了ModelLoader机制,如果我们想增加一种Request,我们只要开发对应的ModelLoader即可。
有了ModelLoader,其实是不够的,它只是用来判断这个Request是否能否处理,为了能真正的加载请求,Glide引入了DataFetcher,不同的方式对应一个不同的DataFetcher,两者职责分离,这是因为同一种Request其实有很多加载方式,比如从网络加载,从磁盘加载等等,非常复杂,所以这里独立出一个DataFetcher。其中LoadData只是对DataFetcher的一种包装,多包含了一些信息而已。

2.2 小结

现在,我们根据传入的请求具体类型(比如url还是file还是字节数组),通过遍历所有的ModelLoader判断该ModelLoader能否处理这种请求,然后用该ModelLoader中的DataFetcher去具体加载这个请求。

3. 从Data到Resource的设计——解码和转码模块设计

有了ModelLoader和DataFetcher机制,Glide已经能方便的将一个原始请求从不同的地方加载到内存中了,这个时候这份数据还只是单纯的二进制数据(携带了格式数据)而已,我们称其为Data,现在需要进行解码过程,剔除原始的格式信息,然后拿原始信息重新编码,将其转化成不同的格式,比如将一个jpg先解码然后转码成Bitmap,或者转码成Gif,解码以及转码后的数据我们称其为Resource。现在面临的问题还是一样的:
由于框架的设计决定了需要解码的格式是不定的,要转码的格式也是不定的,如何高效的组织这个过程呢?
这个和Request被加载的过程类似,这里采用的是模板方法设计模式:

解码转码类图.png

可以看到,这里我们能从Registry中获取所有的ResourceDecoder和ResourceTranscoder,然后判断哪个解码器或转码器适合当前格式,直接调用相关的decode和transcode方法就可以了。
以这种方式,我们能随意扩展不同格式的解码和转码了。

4. 从Resource到Resource的设计——资源变换操作

资源解码并转码后,由于某些特殊的需求,我们是不能直接使用的,比如有圆角需求,透明度需求等等,完成这步转换的,就是Transformation。由于这一步转换是可选的,和上面两步都不同必须进过的步骤不同,这里的Transformation就不能存在一个地方主动去取,必须是得构建这整个流程的时候指定使用哪个Transformation,这里没有什么复杂的架构,大家了解下Transformation的大致情况即可:


Transformation类图一览.png

5. 从Resource到显示在Target上的设计——资源显示操作

现在我们走到了最后一步,需要将符合条件的Resource显示在指定的Target上,当然具体如何显示细节本文不讨论,我们主要关注的是显示时候的动画操作,也就是经过Transition的 transition()。这一步和上面一步类似,是否需要使用Transition和使用哪个Transition都是由请求时用户决定的,因此这里也没有复杂架构,大家看下Transition的组成即可:


Transition.png

6. 总结

其实从总体架构上来说,Glide的设计无疑是非常完美的,每一个步骤都是面对接口编程,可以随意新增或修改其中的某一步,扩展性非常强,这虽然让架构变的更加复杂,但这点代价是值得的。以这个架构来说,只要Android不死,Glide都能一直用下去。
最后,本文只是简单的给大家一个Glide的大致流程,每个流程是怎么回事,让大家有个概念,甚至连最复杂的缓存都没提到,更不用说每一步的具体流程了,针对这些,我将会继续写一系列的文章,希望能将Glide说清楚。最后的最后,文章都是我个人的理解,如果有错误,恳请大家指正!

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

推荐阅读更多精彩内容