为什么此代码会导致重组(jetpack compose)

dyl*_*won 6 android android-jetpack-compose

我不知道为什么在我的代码中我输入“hi”的文本总是被重新组合。文本被固定为“hi”,onClick 还使用 uiEvent 维护了记住的实例。

即使 uiState.isLoading 改变了,它也与 Text 无关,所以我预计重组会被跳过,但重组总是在 Text 改变时发生。

这是我的代码:

UiState 数据类

data class UiState(
    val isLoading: Boolean
)
Run Code Online (Sandbox Code Playgroud)

UiEvent 接口。

@Immutable
interface UiEvent {
    fun onClick()
}
Run Code Online (Sandbox Code Playgroud)

可组合的

@Immutable
interface UiEvent {
    fun onClick()
}
Run Code Online (Sandbox Code Playgroud)

chu*_*ckj 7

我认为您要问的是为什么在重组Text时不跳过MyScreen。原因是每次都会创建一个新的可点击修改器。考虑记住整个修饰符,例如:

@Composable
fun MyScreen(
    viewModel: MyViewModel = hiltViewModels()
) {
    val uiState = viewModel.uiState.collectAsStateWithLifecycle()
    val modifier = remember(viewModel) {
        val event = object: UiEvent {
            override fun onClick() {
                viewModel.action()
            }
        }
        Modifier.clickable { event.onClick() }
    }
    Text(  // why recomposition?
        modifier = modifier,
        text = "hi"
    )
    if (uiState.isLoading) {
        Text(text = "isLoading")
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,将作为参数添加到记住中,以确保在发生更改时创建viewModel新版本。clickable()viewModel

compose 编译器插件应该能够识别::语法并remember为您执行此操作,就像处理 lambda 语法一样,但现在还不行。此外,clickable()对于相同的参数,总是返回一个不等于先前版本的修饰符,但这将在 1.5 中得到修复(以及许多其他与性能相关的修复)clickable()。现在,您可以通过记住整个修饰符来解决这些限制。

  • 哇。我花了几个小时才发现可点击修饰符正在返回一个新实例,因此不履行“@Stable”的合同。不管怎样,谢谢你的回答。这很有帮助! (2认同)