【一、前言Lottie简介与使用】
1、Lottie简介
Lottie是Airbnb开源的跨平台动画库,支持iOS、Android、React Native 和 Web 等平台。它可以解析使用 Bodymovin 导出为 json 的 Adobe After Effects 动画,允许应用程序像使用静态图像一样轻松使用动画。
Android库地址:https://github.com/airbnb/lottie-android
iOS库地址:https://github.com/airbnb/lottie-ios
Lottie资源库:https://lottiefiles.com/
2、Lottie的使用流程
(1). 动效设计人员在Adobe After Effects中设计动画;
(2). 动效设计人员通过Adobe After Effects的Bodymovin插件导出记录动画信息的JSON文件;
(3). 开发人员使用Lottie的开源库读取这份JSON文件进行解析和渲染。
3、Lottie方案的优点
(1). 动画由设计使用专业的动画制作工具Adobe After Effects来实现,使动画实现更加方便,动画效果也更好,100% 还原。
(2). 使用lottie方案,json文件大小会比gif文件小很多,性能也会更好。
(3). 简单的实现、控制动画的播放,开发效率大大提高。
(4). 可动态配置下发,实时替换动画效果。
4、lottie-android 两种引入方式
xml方式
编程方式
5、Lottie实现原理
Lottie使用通过Bodymovin插件导出的json文件作为动画数据源,(json文件把图片中的元素进行来拆分,并且描述每个元素的动画执行路径和执行时间)。Lottie的读取这些数据,然后绘制到屏幕上。
首先要解析json,建立数据到对象的映射,然后根据数据对象创建合适的Drawable绘制到view上,动画的实现可以通过操作读取到的元素完成。具体过程如下所示
json文件——>Component——>Drawable——>View
通过如下3个核心类来来完成整个工作流程
(1). LottieComposition(json->数据对象)
Lottie使用LottieComposition来作为After Effects的数据对象,即把Json文件映射为到LottieComposition,该类中提供了解析json的静态方法
(2). LottieDrawable(数据对象->Drawable)
绘制
Lottie 的核心是 LottieDrawable,它承载了所有的绘制工作,LottieAnimationView则是对LottieDrawable 的封装,再附加了一些例如解析的功能。
(3). LottieAnimationView(绘制)
操作集合,LottieAnimationView继承自 AppCompatImageView,封装了一些动画的操作,具体的绘制委托 LottieDrawable 完成的。
【二、内存泄漏问题背景出现场景】
背景
输入法录音助手SDK测试,录音助手SDK和输入法进程相互独立。
问题场景
(录音助手SDK)首页和(输入法)我的页面切换,发现明显的内存增长趋势。
问题修复插曲
开发同学的账号和机器泄漏不明显,修复其他内存泄漏后,开发提交检验;但测试同学机器和账号内存泄漏易复现,最终开发测试一同对比定位,复现。
问题修复
修复后,(助手SDK)首页和(输入法)我的页面切换,最终退出SDK,可见内存最终可以恢复平稳,和起始内存差异不大;助手SDK进程的CPU占用0%。
【三、问题定位与分析】
结论:lottie本身的状态处理有bug 导致泄漏了,MemoryLeak in LottieDrawable。
lottieview在detach的时候会停止动画,如果无法停止,就会导致内存泄漏。
小编场景分析:
进首页->退出,很有可能动画还没开始,就要被停止掉,所以就释放不了资源。
代码分析
lottie依赖onDetachedFromWindow停止动画,动画的play可能是异步的,在onDetachedFromWindow 中会判断当前是否在动画中,如果在动画中才会停止动画,删除异步任务,但此时可能并不再动画中,但有一个已经post出去的异步任务,在detach 后动画会执行。
加载动画是异步的,加载完成才会进入播放状态。如果compositionLayer == null 的时候,会加入到task里,没开始播放。
播放开始了running= true;
removeFrameCallback,running = false;
onDetachedFromWindow停止动画
detach 处理时,先判断是不是播放状态,如果是播放状态running == true,才会去 cancel。但有可能加载动画完成发生在 detach 之后。
官方:Lottie的新版本修改了这个问题,但Lottie 3.0.0以上版本必须要项目支持android X。
评估:这个改动需要把所有第三方框架都进行升级,对小编所在项目成本太高,暂不可行。
目前处理:重写LottieAnimationView继承,然后在ondetachedfromwindow里直接cancle。无论是否在动画中都调用一次 cancelAnimation, 取消动画,删除可能存在的异步任务。
【参考】
Lottie 官方文档:http://airbnb.io/lottie/
Lottie Github:https://github.com/airbnb/lottie-android
https://zhuanlan.zhihu.com/p/41339812
https://juejin.im/entry/58a324d12f301e00695da316
https://juejin.im/post/5a31ea836fb9a0451705367c
https://juejin.im/post/5d19fb53e51d45598611b9b6