android-gif-drawable 加载 Gif图片的 细节分析

Gif 加载对比

android-gif-drawable 来加载gif 和glide 对比一下

注意这里的GifDrawable 和 glide里面的不是一个

kotlin 复制代码
Thread() {  
run {  
var futureTarget: FutureTarget<File?>? = Glide.with(this)  
.downloadOnly()  
.load(url)  
.submit() // 一次性加载了 整个gif 图片的大小  
val drawable = GifDrawable(futureTarget?.get()!!.path)  
runOnUiThread {  
imageview.setImageDrawable(drawable)  
}  
}  
}.start()

加载gif 时的性能对比可以看出来整体加载曲线很平稳,且内存占用只有62.8mb

可以看下具体的内存占用分布

再来看看原生glide 加载 gif的 场景:

可以看出来 使用glide 原生加载gif的时候 峰值内存达到175mb

平稳以后也有 接近115mb的内存占用

加载流程

可以看出来这个Drawable的构造方式有很多

我们一般都是传一个固定file path进去,

可以看出来 在构建Drawable的过程中,会调用一个c++方法 去打开这个文件

这个jni 方法 主要就是 返回一个GifInfo对象的指针地址

在我们对imageview 调用了setImageViewDrawable方法以后, 其实会有一系列的回调到我们的drawable中

其中最重要的就是draw 和invalidateself 2个方法

扯远了, 我们回到之前的 GifDrawble 构造方法中来

doWork 我们最关注的 就是 红框中的2个步骤

第一个就是renderFrame

最后调用的是这个jni方法,参数其实就是一个空的bitmap

这个jni方法做的就是把这个bitmap的像素值 按照gif里的帧 给她填满

所以看到这 大家应该有一个感受了, 如果你是在主线程中创建的GifDrawable 那么至少会有两次 耗时操作

一个是读取文件,另外一个就是这里的绘制bitmap中的像素,

**所以我们在用这个gif库的时候 条件允许 可以在子线程去创建GifDrawable **

逐帧播放的逻辑

前文我们跟到了手动调用doWork的逻辑,在GifDrawable 构造函数 中,doWork 除了 解析出 gif的第一帧以外,还发送了一个handler 消息 我们可以跟一下这个handler 消息做了啥

可以看出来 最终还是 将renderTask 放到 一个线程池中去执行了,也就是说 对于这个Gif库来说,从Gif的第二帧 开始 他都是100% 在子线程在做的 帧解析

另外我们也可以看到 相比于Glide,这个库的优点,这个库甚至都没有使用BitmapPool,全程就只有构造函数中 createBitmap 一处调用,所谓的逐帧播放 都是对这个bitmap 内存的反复擦写罢了。

相比于Glide,不但 少了一个GIF本身的文件内存, 甚至 bitmap 对象池都省略了。

相关推荐
omegayy2 小时前
Unity 2022.3.x部分Android设备播放视频黑屏问题
android·unity·视频播放·黑屏
mingqian_chu2 小时前
ubuntu中使用安卓模拟器
android·linux·ubuntu
自动花钱机2 小时前
Kotlin问题汇总
android·开发语言·kotlin
行墨5 小时前
Kotlin 主构造函数
android
前行的小黑炭5 小时前
Android从传统的XML转到Compose的变化:mutableStateOf、MutableStateFlow;有的使用by有的使用by remember
android·kotlin
_一条咸鱼_5 小时前
Android Compose 框架尺寸与密度深入剖析(五十五)
android
在狂风暴雨中奔跑5 小时前
使用AI开发Android界面
android·人工智能
行墨5 小时前
Kotlin 定义类与field关键
android
信徒_6 小时前
Mysql 在什么样的情况下会产生死锁?
android·数据库·mysql
大胡子的机器人6 小时前
安卓中app_process运行报错Aborted,怎么查看具体的报错日志
android