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

Jetpack Compose中固定文本Text组件为何频繁重组?

问题原因及解决方案

为什么显示"hi"的Text会跟着重组?

Jetpack Compose的重组规则是:当父Composable发生重组时,它内部的所有子Composable都会被触发重组检查。你的MyScreen会在uiState.isLoading变化时发生重组,所以里面的那个Text组件也会被调用执行重组流程——哪怕它的参数看起来没有变化。

这里要区分「重组」和「UI重绘」:重组是指Composable函数被调用执行,而UI重绘是指实际更新界面元素。即使Text的参数没变化,重组过程还是会发生,但Compose会跳过最终的UI重绘步骤。如果想连重组都避免,就需要做额外优化。

另外,你用remember保留了UiEvent实例,uiEvent::onClick的函数引用是稳定的,但因为Text直接写在MyScreen内部,父重组时还是会触发它的重组检查。

如何避免不必要的重组?

最直接且符合Compose最佳实践的方式是把这个Text提取成独立的Composable函数:

@Composable
fun HiText(onClick: () -> Unit) {
    Text(
        modifier = Modifier.clickable(onClick = onClick),
        text = "hi"
    )
}

然后在MyScreen中调用这个独立的Composable:

@Composable
fun MyScreen(
    viewModel: MyViewModel = hiltViewModels()
) {
    val uiState = viewModel.uiState.collectAsStateWithLifecycle()
    val uiEvent = remember {
        object : UiEvent {
            override fun onClick() {
                viewModel.action()
            }
        }
    }
    
    HiText(onClick = uiEvent::onClick)
    
    if (uiState.value.isLoading) {
        Text(text = "isLoading")
    }
}

当uiState.isLoading变化时,HiText的参数onClick没有发生变化(因为uiEvent是remember保存的稳定实例),Compose会直接跳过HiText的重组流程,彻底避免不必要的函数调用。

补充:原代码中uiState.isLoading需要改为uiState.value.isLoading,因为collectAsStateWithLifecycle()返回的是State<UiState>,必须取value才能拿到内部的isLoading属性。

内容的提问来源于stack exchange,提问作者dylan.kwon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 12:37:28