You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中LazyColumn为何每约30项就重建一次?

Jetpack Compose LazyColumn滚动时频繁重组的问题解决

问题详情

刚开始尝试Jetpack Compose,发现滚动简单列表时优化效果很差,即使在release构建中也是如此。添加日志后发现列表有时会自行重建,每滚动约30项就会触发一次重建。

代码示例

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun MissionsList() {
    val list = remember { (0..75).map { it.toString() } }
    LazyColumn(
        verticalArrangement = Arrangement.spacedBy(22.5.dp)
    ) {
        Log.e("LazyColumn", "CREATE")
        items(
            count = list.size,
            key = { list[it] }
        ) {
            Card(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(100.dp),
                elevation = 0.dp,
                shape = RoundedCornerShape(20.dp),
                onClick = { /*TODO*/ }
            ) {
                Log.e("card", "${list[it]}")
                Text(
                    text = list[it],
                    modifier = Modifier.padding(15.dp)
                )
            }
        }
    }
}

日志输出

15:20:30.738 LazyColumn               E  CREATE
15:20:30.810 card                     E  0
15:20:30.828 card                     E  1
15:20:30.841 card                     E  2
15:20:30.866 card                     E  3
15:20:30.879 card                     E  4
15:20:31.250 Chip                     E  1
15:20:36.404 card                     E  6
15:20:36.496 card                     E  7
15:20:36.560 card                     E  8
15:20:36.645 card                     E  9
15:20:36.730 card                     E  10
15:20:36.840 card                     E  11
15:20:37.043 card                     E  12
15:20:38.324 card                     E  13
15:20:38.381 card                     E  14
15:20:38.417 card                     E  15
15:20:38.449 card                     E  16
15:20:38.478 card                     E  17
15:20:38.504 card                     E  18
15:20:38.529 card                     E  19
15:20:38.560 card                     E  20
15:20:38.570 card                     E  21
15:20:38.579 card                     E  22
15:20:38.610 card                     E  23
15:20:38.653 card                     E  24
15:20:38.685 card                     E  25
15:20:38.694 card                     E  26
15:20:38.717 card                     E  27
15:20:38.761 card                     E  28
15:20:38.782 card                     E  29
15:20:38.793 card                     E  30
15:20:38.820 card                     E  31
15:20:38.859 card                     E  32
15:20:38.892 card                     E  33
15:20:38.921 card                     E  34
15:20:38.972 card                     E  35
15:20:39.006 card                     E  36
15:20:39.020 LazyColumn               E  CREATE
15:20:39.027 card                     E  37
15:20:39.045 card                     E  30
15:20:39.047 card                     E  31
15:20:39.048 card                     E  34
15:20:39.066 card                     E  35
15:20:39.069 card                     E  32
15:20:39.070 card                     E  33
15:20:39.072 card                     E  36
15:20:39.131 card                     E  38
15:20:39.169 card                     E  39
15:20:39.218 card                     E  40
15:20:39.281 card                     E  41
15:20:39.354 card                     E  42
...

问题分析与解决方法

1. 日志位置导致的误解

你看到的LazyColumn CREATE日志,是因为把Log语句直接放在了LazyColumn的content lambda内部。这个lambda会在LazyColumn的滚动状态变化时被重新调用,这是Compose的正常行为,并不代表整个LazyColumn组件被重建。如果想正确追踪LazyColumn的初始化,应该用LaunchedEffect(Unit)包裹日志,避免每次重组都打印。

2. 列表项的重组优化

滚动时部分项的日志重复打印,是因为你没有将列表项提取为独立的、稳定的Composable。Compose会基于参数的稳定性来判断是否需要重组组件,把项的逻辑抽离成单独的Composable后,只有当参数变化时才会触发重组:

@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun MissionItem(text: String, onClick: () -> Unit) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .height(100.dp),
        elevation = 0.dp,
        shape = RoundedCornerShape(20.dp),
        onClick = onClick
    ) {
        Text(
            text = text,
            modifier = Modifier.padding(15.dp)
        )
    }
}

然后在LazyColumn中调用这个Composable:

items(
    count = list.size,
    key = { it } // 静态列表用索引作为key足够稳定,也可以继续用list[it]
) { index ->
    MissionItem(text = list[index], onClick = { /*TODO*/ })
}

3. 稳定滚动状态

手动创建并remember滚动状态,传递给LazyColumn,可以避免因内部状态变化导致的不必要重组:

val scrollState = rememberLazyListState()
LazyColumn(
    state = scrollState,
    verticalArrangement = Arrangement.spacedBy(22.5.dp)
) {
    // ...
}

4. 移除调试日志

不要在Composable的body中直接放置Log语句,高频重组的场景下会影响性能,也会干扰对重组行为的判断。调试时建议使用Compose专用的工具(如Layout Inspector)来查看组件重组情况。

内容的提问来源于stack exchange,提问作者Ben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 19:10:31