渲染性能优化
问题
如何保证 Android 应用流畅的 60fps 渲染?常见的掉帧原因有哪些?
答案
渲染流水线
Android 的渲染目标是 60fps,即每帧必须在 16.67ms 内完成。
常见卡顿原因
| 原因 | 说明 | 解决方案 |
|---|---|---|
| 布局层级过深 | 多层嵌套 LinearLayout | 使用 ConstraintLayout 扁平化 |
| 过度绘制 | 同一像素被绘制多次 | 移除不必要的背景色 |
| 主线程耗时操作 | IO/网络/复杂计算 | 移到子线程/协程 |
invalidate() 频繁调用 | 不必要的重绘 | 使用局部更新 |
| RecyclerView 未优化 | 列表滑动卡顿 | ViewHolder 复用、预加载 |
过度绘制检测
开发者选项 → 调试 GPU 过度绘制:
| 颜色 | 过度绘制次数 | 说明 |
|---|---|---|
| 无色 | 0 | 绘制 1 次(正常) |
| 蓝色 | 1 | 绘制 2 次(可接受) |
| 绿色 | 2 | 绘制 3 次(需关注) |
| 粉色 | 3 | 绘制 4 次(需优化) |
| 红色 | 4+ | 绘制 5 次以上(必须优化) |
优化手段
// 1. 使用 ConstraintLayout 减少层级
// ❌ 3 层嵌套
LinearLayout
└── LinearLayout
└── LinearLayout
// ✅ 1 层
ConstraintLayout
// 2. 移除不必要的背景
// ❌ Activity 和根布局都设了白色背景
// ✅ 在 Activity 的 theme 中去掉 windowBackground
<style name="AppTheme" parent="Theme.Material3.DayNight">
<item name="android:windowBackground">@null</item>
</style>
// 3. ViewStub 延迟加载
// 不经常显示的布局使用 ViewStub
<ViewStub
android:id="@+id/error_stub"
android:layout="@layout/error_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
使用 Systrace / Perfetto 分析
# 抓取 trace
python systrace.py -o trace.html gfx view wm am
# 或使用 Perfetto(推荐)
adb shell perfetto -o /data/misc/perfetto-traces/trace.pb -t 10s -b 32mb \
sched freq idle am wm gfx view
常见面试问题
Q1: 如何判断掉帧的原因?
答案:
- Systrace / Perfetto:查看是否有超过 16ms 的帧,分析 Choreographer 的
doFrame耗时 - GPU Profiling:开发者选项 → GPU 呈现模式分析,查看绿色线以上的条形图
- StrictMode:检测主线程 IO 操作
Q2: Compose 和传统 View 的渲染性能差异?
答案:
- Compose 跳过了 XML 解析和 inflate 过程,使用编译时代码生成
- Compose 的智能重组只重绘变化部分
- 但 Compose 在 debug 模式下性能明显差于 release,测试性能必须用 release 版本
- 对于复杂的列表场景,Compose
LazyColumn和 RecyclerView 性能基本持平