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

