Lottie 播放卡顿——帧率低、掉帧、内存泄漏
先定位:是哪一端卡
卡顿问题有三种类型,排查方向不同:
| 类型 | 表现 | 排查方向 |
|---|---|---|
| 设备帧率低 | 整个界面卡,包括非 Lottie 区域 | 设备性能 / 渲染器 / 动画复杂度 |
| Lottie 独占卡顿 | 停播 Lottie 就恢复流畅 | 动画本身 / SDK 版本 |
| 内存泄漏 | 页面退出后内存不释放,下次进来更卡 | 代码实现 / 生命周期管理 |
动画本身导致的卡顿
图层数量过多
一个动画里图层数量超过 100 层时,每一帧都需要遍历所有图层并计算属性变化——这个开销在低端 Android 和老款 iOS 上会很明显。
解决:
- AE 里用 Precompose(Ctrl+Shift+C)把内部复杂结构合并成单个形状图层。
- Creator 里用 "Simplify" 工具简化路径。
- 拆分动画——一个大动画拆成几个小动画,按需加载。
位图图层过大
动画里如果用了 2000x2000 以上的位图,每帧都要解码和缩放。位图在不同像素密度的屏幕上表现还不一致。
解决:位图最大控制在 500x500 以内;能全部用矢量就全部用矢量。
表达式没清理干净
如果 JSON 里还残留了表达式("ty": "expr" 类型的节点),渲染引擎每帧都要执行表达式——这比纯关键帧动画慢很多。
检查:用文本编辑器打开 JSON,搜索 "exp" 或 "expressions" 字段——如果有,回到 AE Convert to Keyframes 重新导出。
渲染器选择
Web 端
- SVG 渲染器:最常用,质量好。但 DOM 节点多(每个 Lottie 图层对应一个 SVG 元素)时,浏览器渲染性能下降。
- Canvas 渲染器:性能更好,特别是图层多的时候。但某些 SVG 特性(比如渐变)Canvas 渲染不精确。
- canvas 渲染器的优势:大量小图形的动画(比如粒子效果)用 canvas 明显比 SVG 流畅。
切换方式:
lottie.loadAnimation({ renderer: 'canvas', /* ... */ });
Android 端
- 默认硬件加速(View 的 hardwareAccelerated 默认 true)。
- 如果你的 Activity 或 ViewGroup 设置了
android:layerType="software"——立刻去掉。软件加速渲染 Lottie 必然卡。 - 避免在动画播放期间频繁操作 View 的
requestLayout()/invalidate()。
iOS 端
lottie-ios 默认用 Core Animation 渲染——性能没问题。但:
- 如果同时在一个页面上创建了多个 LottieAnimationView,都在无限循环,CPU 占用会累计。
- 页面里超过 3 个同时播放的动画 → 考虑把非可见的暂停。
内存泄漏
典型场景
| 场景 | 泄漏点 |
|---|---|
| React / Vue 组件卸载 | effect 里没调 anim.destroy() |
| Activity / Fragment 退出 | LottieAnimationView 的 onDetachedFromWindow 没停播 |
| RecyclerView ViewHolder 复用 | 同一个 LottieAnimationView 反复设置不同动画但没 cancel |
| 远程 URL 加载 | Composition 被 Lottie 内部缓存但不释放 |
原则
谁创建动画,谁负责销毁:
// React useEffect 里
useEffect(() => {
const anim = lottie.loadAnimation({ /* ... */ });
return () => anim.destroy(); // 必须清理
}, []);
// Android Fragment
override fun onPause() {
super.onPause()
animationView.cancelAnimation()
}
override fun onDestroyView() {
super.onDestroyView()
animationView = null // 释放引用
}
检查方式
- Android:Android Studio Profiler → Memory → Leaks 检测。
- iOS:Instruments → Allocations。
- Web:Chrome DevTools → Memory → Take Snapshot。