android 为什么在回调中调用ViewModel时会发生重组?

oknwwptz  于 2022-11-27  发布在  Android
关注(0)|答案(2)|浏览(139)

我完全搞不懂作曲的概念。我有一个代码

@Composable
fun HomeScreen(viewModel: HomeViewModel = getViewModel()) {
    Scaffold {
        val isTimeEnable by viewModel.isTimerEnable.observeAsState()
        Column(
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Black),
        ) {
            Switch(
                checked = isTimeEnable ?: false,
                onCheckedChange = {
                    viewModel.setTimerEnable(it)
                },
            )
            Clock(viewModel.timeSelected.value!!) {
                viewModel.setTime(it)
            }
        }
    }
}

@Composable
fun Clock(date: Long, selectTime: (date: Date) -> Unit) {
    NumberClock(Date(date)) {
        val time = SimpleDateFormat("HH:mm", Locale.ROOT).format(it)
        Timber.d("Selected time: time")
        selectTime(it)
    }
}

为什么Clock小工具在我点击开关时会重组。如果我从Clock小工具中删除selectTime(it)行,回调重组不会发生。1.0.2

z31licg0

z31licg01#

这是因为在compose中,你每次都在创建一个新的selectTime lambda,所以重新组合是必要的。如果你传递setTime函数作为引用,compose会知道它是同一个函数,所以不需要重新组合:

Clock(viewModel.timeSelected.value!!, viewModel::setTime)

或者,如果你有更复杂的处理程序,你可以remember它。双括号({{ }})在这里很关键,因为你需要记住lambda。

Clock(
    date = viewModel.timeSelected.value!!,
    selectTime = remember(viewModel) {
        {
            viewModel.setTimerEnable(it)
        }
    }
)

我知道这看起来有点奇怪,你可以使用rememberLambda,这将使你的代码更可读:

selectTime = rememberLambda(viewModel) {
    viewModel.setTimerEnable(it)
}

请注意,您需要将所有可能更改的值作为键传递,因此remember将根据需要重新计算。
一般来说,重新组合并不是一件坏事。当然,如果你可以减少它,你应该这样做,但是你的代码应该工作正常,即使它被重新组合了很多次。例如,你不应该在composable里做大量的计算来完成这件事,而是使用side effects
因此,如果重新组合Clock会导致奇怪的UI效果,则可能是您的NumberClock有问题,无法在重新组合后继续存在。如果是这样,请将NumberClock代码添加到您的问题中,以获得如何改进它的建议。

gxwragnw

gxwragnw2#

这是预期的行为。当用户切换开关时,您显然是在修改视图模型中的isTimeEnabled字段(通过调用vm.setTimeenabled)。现在,很明显,视图模型中的isTimeEnabled是一个LiveData示例,您通过在其上调用observeAsState从Composable中引用该示例。因此,当您修改开关的onValueChange中的值时,您实际上是在修改Composable所依赖的状态。

相关问题