什么是重组
Compose 靠函数描述界面。状态一变,Compose 会重新执行相关函数、更新界面——这个过程叫重组。它是声明式的优势:你只管描述,框架负责刷新。
重组本身不是问题,过度重组才是。
这篇把 Compose 性能优化的几个关键点走一遍。
重组为什么会卡顿
一个父状态一变,整屏子函数全重跑,哪怕子项的数据根本没变。列表一长、滚动时每帧都重组一大堆,就掉帧卡顿。屏幕刷新率是固定的,每一帧留给你的时间就那么多,重组花超了这一帧,画面就来不及更新,用户看到的就是卡顿。所以 Compose 性能优化的核心不是把函数写快一点,而是让不该重跑的函数一次都别重跑。
Compose 性能速查
- 重组状态变就重跑,越少越好。
- 懒加载只渲染屏幕内项。
- remember缓存计算,别每帧重算。
让重组跳过不必要的部分
把数据拆细,让只依赖自己数据的子项独立重组。把列表项数据存成不可变对象,数据没变 Compose 就跳过它。越细的拆分意味着越多的跳过机会,滚动也就越省。
@Composable
fun Item(item: RowItem) {
// item 没变就跳过重组
Text(item.title)
}
数据相等就跳,滚动自然顺。
懒加载列表
别用 Column 硬塞几百行。用 LazyColumn,它只渲染屏幕上看得到的那几项,划出去的回收掉。
remember 与状态
别在组合里每帧新建对象或重算大列表。用 remember 缓存结果,让昂贵计算只做一次。派生状态用 remember 包好。
Lint 与基准测试
Compose 自带 Lint 检查常见性能写法。再用基准测试量化一帧耗时,改完有数据对比,不靠感觉。
- 先靠 Lint 排常见写法。
- 懒加载别用 Column 堆列表。
- 基准测试量化前后差异。
实战:优化一个列表项
一个项里格式化时间,原来每次重组都重算。
val time = remember(item.time) {
formatTime(item.time)
}
item.time 没变就直接用缓存。列表滚动顺滑了,重组也省了。Compose 性能优化做到这份上,长列表不再卡。