View 性能优化与卡顿分析
打造 60fps 流畅应用的实战指南
目录
- 性能指标与优化目标
- 卡顿原因分析
- 布局优化
- 绘制优化
- 内存优化
- 调试工具
1. 性能指标与优化目标
60fps 原则
flowchart TB
FPS["60fps = 每帧 16ms"] --> Measure["1. UI 测量(measure)"]
Measure --> Layout["2. UI 布局(layout)"]
Layout --> Draw["3. UI 绘制(draw)"]
Draw --> GPU["4. GPU 渲染"]
GPU --> Jank["超过 16ms = 卡顿"]
卡顿原因
| 原因 |
占比 |
解决方案 |
| 过度绘制 |
40% |
移除不必要的背景 |
| 布局复杂 |
25% |
优化布局层级 |
| 主线程耗时 |
20% |
异步处理 |
| 内存问题 |
15% |
减少 GC |
2. 卡顿原因分析
过度绘制 (Overdraw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <LinearLayout android:background="@color/white"> <!-- 绘制1 --> <FrameLayout android:background="@drawable/bg_card"> <!-- 绘制2 --> <TextView android:background="@color/white" /> <!-- 绘制3 --> </FrameLayout> </LinearLayout>
<LinearLayout android:background="@color/white"> <!-- 只绘制1 --> <FrameLayout android:background="@drawable/bg_card"> <!-- 只绘制2 --> </FrameLayout> </LinearLayout>
|
解决过度绘制
1 2 3 4 5 6 7 8 9
|
ViewDebug.startHotSwapListener(object : ViewDebug.HotSwapListener { override fun onHotSwapComplete() { } })
|
3. 布局优化
Hierarchy Viewer 检测
flowchart LR
subgraph Before["优化前层级"]
B1["LinearLayout"] --> B2["LinearLayout"] --> B3["FrameLayout"] --> B4["TextView"]
end
subgraph After["优化后层级"]
A1["LinearLayout(直接子 View)"] --> A2["TextView"]
end
使用 ConstraintLayout 扁平化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <LinearLayout> <LinearLayout> <LinearLayout> <TextView /> </LinearLayout> </LinearLayout> </LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout> <TextView app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
|
include 与 merge
1 2 3 4 5 6 7 8 9 10 11 12 13
| <merge xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <TextView android:id="@+id/title" app:layout_constraintTop_toTopOf="parent" /> </merge>
<include layout="@layout/title" />
|
4. 绘制优化
减少 onDraw 调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| override fun onDraw(canvas: Canvas) { val paint = Paint() canvas.drawCircle(...) }
class MyView(context: Context) : View(context) { private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = Color.RED } override fun onDraw(canvas: Canvas) { canvas.drawCircle(..., paint) } }
|
使用 Canvas.save()/restore()
1 2 3 4 5 6 7 8 9 10 11
| override fun onDraw(canvas: Canvas) { canvas.save() canvas.rotate(45f) canvas.drawBitmap(bitmap, 0f, 0f, paint) canvas.restore() }
|
硬件加速
1 2 3 4 5 6 7 8
|
<application android:hardwareAccelerated="true">
view.setLayerType(View.LAYER_TYPE_HARDWARE, null) view.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
|
5. 内存优化
避免内存抖动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| override fun onDraw(canvas: Canvas) { val rect = RectF() canvas.drawRect(rect, paint) }
class MyView : View { private val rect = RectF() override fun onDraw(canvas: Canvas) { rect.set(0f, 0f, width.toFloat(), height.toFloat()) canvas.drawRect(rect, paint) } }
|
减少对象创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| fun process() { val list = ArrayList<String>() list.add("item") }
class Processor { private val buffer = ArrayList<String>(10) fun process() { buffer.clear() buffer.add("item") } }
|
6. 调试工具
Systrace
1 2 3 4 5
| python systrace.py -t 10 -o trace.html sched gfx view wm
|
Perfetto
1 2 3 4 5 6 7 8 9 10 11
| adb shell perfetto \ -c - --txt \ -o /data/misc/perfetto-traces/trace \ <<EOF buffers: { size: 6348608 } data_sources: { config { name: "linux.ftrace" } } data_sources: { config { name: "linux.process_stats" } } data_sources: { config { name: "android.surfaceflinger.frametimeline" } } duration_ms: 10000 EOF
|
Layout Inspector
1 2 3 4
| 使用步骤: 1. Tools > Layout Inspector 2. 选择设备/进程 3. 查看层级、属性、渲染效果
|
开发者选项
| 选项 |
作用 |
| GPU 过度绘制 |
显示过度绘制区域 |
| GPU 渲染分析 |
显示每帧渲染时间 |
| 关闭硬件加速 |
测试软件渲染 |
性能优化 checklist
flowchart TB
Checklist["View 性能优化 checklist"] --> LayoutOpt["布局优化<br/>ConstraintLayout / 移除背景 / include + merge / 精简 padding"]
Checklist --> DrawOpt["绘制优化<br/>避免 onDraw 创建对象 / 硬件加速 / 减少 clipPath / save/restore"]
Checklist --> MemoryOpt["内存优化<br/>避免内存抖动 / 减少对象创建 / 使用对象池"]
Checklist --> Tools["工具<br/>Hierarchy Viewer / Layout Inspector / Systrace / Perfetto"]
面试常问
| 问题 |
答案 |
| 16ms 包含什么? |
measure + layout + draw + GPU 渲染 |
| 过度绘制如何检测? |
开发者选项 GPU 过度绘制 |
| onDraw 为什么不能创建对象? |
触发 GC 导致卡顿 |
| ConstraintLayout 优势? |
扁平化、性能好 |
总结
flowchart TB
PerfCore["View 性能优化核心"] --> P1["减少布局层级"]
PerfCore --> P2["避免过度绘制"]
PerfCore --> P3["避免 onDraw 创建对象"]
PerfCore --> P4["使用硬件加速"]
PerfCore --> P5["使用调试工具检测"]
相关文章: