【问题标题】:Why recomposition happens when call ViewModel in a callback?为什么在回调中调用 ViewModel 时会发生重组?
【发布时间】:2021-09-07 23:54:25
【问题描述】:

我完全混淆了撰写概念。 我有代码

@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

【问题讨论】:

    标签: android viewmodel android-jetpack-compose android-viewmodel


    【解决方案1】:

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

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

    或者,如果你有更复杂的处理程序,你可以remember它:

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

    请注意,您需要将所有可能更改的值作为键传递,因此 remember 将根据需要重新计算。


    一般来说,重组并不是一件坏事。当然,如果你可以减少它,你应该这样做,但是你的代码即使被多次重组也应该可以正常工作。例如,您不应该直接在可组合内执行繁重的计算来执行此操作,而应使用side effects

    因此,如果重构 Clock 会导致奇怪的 UI 效果,那么您的 NumberClock 可能有问题,无法在重构后幸存下来。如果是这样,请将NumberClock 代码添加到您的问题中,以获取有关如何改进它的建议。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 2010-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多