如何扩展Glide 框架

为什么要扩展Glide框架

前面的文章介绍过 glide 在加载gif的时候 一些天生缺陷, 以及不支持低android版本的动图webp播放, 当然为了简单你可以直接修改glide 源代码 然后直接发布你自己的定制版本 以达到扩展功能的目的

但是这样做 等于你屏蔽了以后glide的功能更新了,以后你和官方的glide 就是两条路了。

其实本身glide 有非常好的源码框架,大部分逻辑都是接口之间互相调用,扩展性非常好,我们可以弄清楚这些接口 实现的注意点, 这样可以非常方便的扩展甚至修改我们glide的功能。

Registry 与 ResourceDecoderRegistry

这个类其实是相当关键的一个类,大部分你要扩展的Glide 功能 其实都要通过这个类进行,看注释 就是管理组件使用的,这些组件包括 编码组件 解码组件,加载组件

其中最关键的就是解码组件了

这个解码组件看注释 是告诉你 这里是存储 每种类型的 解码器列表的,而且是有优先级的

为啥会有优先级? 因为每一种 bucket 对应的是一个List的 decoders,list显然是有顺序的吧 你找到一个 就结束了 就不会往后找了,那显然你 这个list 顺序在前的 被选中的概率肯定更高的, 所以这里是有顺序的

注意decoders里面存储的 ,注释也写清楚了 一般都是ResourceDecoders的借口

他提供了两种添加解码器的方法

区别就是 到底在解码器的 list 尾部添加还是头部添加

默认情况下 我们的bucket 类型 也就是glide内置的类型 就是这么多

默认情况下 我们会在RegistryFactroy 下注册

可以看出来bitmap就是在这里注册的 解析

如何理解这里的参数呢?

bucket 和 resourceClass 往往是一个意思,就是你想解析出来的东西,比如上述我们想解析出来bitmap

dataClass 就代表 数据源是什么,最后一个就是解码器了

那么这里的解码关系 初始化好以后 在哪里被使用到呢?

还是在Registry的 getDecodePaths方法中

可以看下调用链关系 其实是在DecodeJob中被调用

这个decode本质上是一个线程,这里就不多说了

Downsampler 的作用

在上面的分析过程中,我们碰到过 init方法,这个方法可以说是 glide 最核心的方法了,以后扩展的思路都是从这里拓展而来

我们这第一个要关注的东西就是这个DownSampler, 我们来好好分析一下这个东西是干啥的

要搞清楚 他是干啥的,首先要弄清楚 他的几个参数, 其中 bitmappool 和 imageHeaderParser 这个我们之前glide-gif 分析中 已经讲过了,直接跳过,我们可以看下 这个arrayPool

这个东西本质上是一个数组缓存,在glide的代码中 他主要 缓存的是int 或者是byte数组

他的实现只有一个 就是LRU

其实在Gif的解析过程中么,这个arraypool 是频繁被使用的

也不用理解的太玄幻,就理解成这里是一个 类似于对象池的东西就可以了,只不过这里是一个数组对象池,仅此而已。

你如果是扩展Glide的人,99% 你是不会重写BitmapPool和ArrayPool的, 直接用默认的实现就可以,如果说BitmapPool是你必须要使用的,那么ArrayPool 你甚至可以不使用,个人理解这里的性能提升不会太明显。

但是大家要知道有这么个东西 能起到什么作用

DownSample 最重要的工作就是 对图片的解码

构造出来的DownSample对象 其实也是被decoder直接调用的

我们在加载一张png图片时 往往也是通过downsampler 真正去解码的

不过目前关于Downsampler,glide官方并没有 抽象成interface,而是直接给了个final的类 ,所以如果我们自己去扩展glide 时候

有需要用到这个东西,往往都是拷贝出来以后 改一下名字,然后修改其中的部分逻辑。这个是比较痛苦的

这会导致 后面更新glide 版本的时候 这里会发生兼容性问题。

这点一定要注意

普通的静态webp 是如何处理的?

这个问题其实有必要思考一下的,gif是android 默认不支持,所以需要独立的 解码 decoder,但是像png 静态webp ,jpg 这种 glide 怎么decode的? 对于普通的webp 其实走的是这个decoder

注意了这个decoder 其实在gif decoder 之后,也就是说 对于glide来说 是先 判断是不是动态图 再看静态图

而且这个静态图的deocoder 默认返回true 就是我一定可以解析出这个图片

最终是走的这个方法

再跟下去

恩 就是走的bitmap的系统方法,到这里 普通图片的分析就结束了

glide 中 webp 动图的展示逻辑

之前我们在其他的文章过 分析过 glide 展示gif 图片的逻辑,现在分析一下 glide 是如何展示 webp动图的。 这里我们首先要明确一下,从 android9 开始 系统自带可以展示webp动图的能力了

这与之前网上流传的 只有fresco 能加载webp动图,glide不行 ,这个说法是不正确的。

准确的说,glide因为没有内置 webp的 解码库,所以<android9的版本 不支持 webp动图。但是fresco内置了,所以fresco可以展示 <android9 的webp

当发现是webp动图的时候

这里的关键其实就是 利用了ImageDecoder 来做动图的解析,注意了这个类是android系统自带的。一般都是androidp 以上才能正常使用

其实在glide的初始化过程中

我们可以发现 他也是在android9上 才启动该解析

而在低于android9的版本中 则是走的默认的bitmap解析流程

webp的文件格式解析

可以看下这个文档 developers.google.cn/speed/webp/...

单独拿这个来说 是因为 这里涉及到如何扩展 glide以后可以解析更多其他格式的图片。 应该来说 所有图片格式提出来以后 都会有一个基础的c代码给你做编解码使用。

我们通常不会自己去写图片格式的编解码,但是 当你想扩展glide的 图片解析的时候 你通常需要在 java/kotlin中 去解析 一下 这个图片是否符合某个格式要求, 一般来说 大部分的格式 文件头 都是一段magic number判断即可,但是对于webp这种会稍微复杂一点,我们不但要判断 他是不是webp格式 还要判断这个webp格式 是不是支持动图播放,这个就稍微复杂一点,这里我介绍一下 实现的思路,其实代码 在glide中都有,只是大部分人直接看是看不懂的,我这里介绍一下 如何从文档中 来获取实现判断webp 是否支持动图的方法

最主要的就是要学会看图

从这个图可知

webp的文件头 固定 12个bytes, 然后vp8x 固定 4个bytes 这就是16个bytes了 对吧

第17个bytes 就是 判断是否是动图的关键了, 每个bytes是8个bit, 第7个bit的值 就是我们关心的是否支持动图了

在mac上 我们可以用 hex find 这个软件来方便的看二进制

他默认是16进制的

我们可以参照 上图的配置 把二进制的展示也打开

找一个动态的webp图片打开如下:

这里灰色选中部分 就是4个bytes,我们直接看红框中的就是第17个字节了

看下 这个bytes中的 第7位。。。

其实glide的判断也是用类似的逻辑

具体代码就不写了,很简单。大家知道以后解析二进制文件的参数即可

ImageDecoder介绍

介绍这个主要是强调一下,android9以后 解析图片的新方式,比bitmap 要方便很多, bitmap你要想解析一下动图很麻烦,看看glide对gif的实现就知道了

但是如果是ImageDecoder这个api 则做动图的展示就很简单了,成本极低,

官方文档

kotlin 复制代码
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {  
lifecycleScope.launch {  
val drawable = withContext(Dispatchers.IO) {  
ImageDecoder.decodeDrawable(ImageDecoder.createSource(resources, R.mipmap.dy))  
}  
imageview.setImageDrawable(drawable)  
if (drawable is AnimatedImageDrawable) {  
drawable.start()  
}  
}  
}
相关推荐
小白也想学C5 分钟前
Android 功耗分析(底层篇)
android·功耗
曙曙学编程12 分钟前
初级数据结构——树
android·java·数据结构
闲暇部落2 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX4 小时前
Android 分区相关介绍
android
大白要努力!5 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee5 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood6 小时前
Perfetto学习大全
android·性能优化·perfetto
Dnelic-9 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen11 小时前
MTK Android12 user版本MtkLogger
android·framework
长亭外的少年18 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin