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 对象池都省略了。

相关推荐
居然是阿宋1 小时前
Kotlin高阶函数 vs Lambda表达式:关键区别与协作关系
android·开发语言·kotlin
凉、介1 小时前
PCI 总线学习笔记(五)
android·linux·笔记·学习·pcie·pci
小贾要学习2 小时前
【C++】继承----下篇
android·java·c++
投笔丶从戎4 小时前
Kotlin Multiplatform--01:项目结构基础
android·开发语言·kotlin
Lary_Rock5 小时前
Android 编译问题 prebuilts/clang/host/linux-x86
android·linux·运维
王江奎6 小时前
Android FFmpeg 交叉编译全指南:NDK编译 + CMake 集成
android·ffmpeg
limingade6 小时前
手机打电话通话时如何向对方播放录制的IVR引导词声音
android·智能手机·蓝牙电话·手机提取通话声音
hepherd7 小时前
Flutter 环境搭建 (Android)
android·flutter·visual studio code
_一条咸鱼_7 小时前
揭秘 Android ListView:从源码深度剖析其使用原理
android·面试·android jetpack