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

2024-03-05

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

@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)
    }
}

Why Clock当我点击开关时,小部件会重新组合。如果我删除线selectTime(it) from Clock小部件回调重组不会发生。 撰写版本:1.0.2


这是因为就撰写而言,您正在创建一个新的selectTime每次都是 lambda,因此需要重新组合。如果你通过了setTime函数作为参考,compose 会知道它是同一个函数,因此不需要重新组合:

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

或者,如果您有更复杂的处理程序,您可以remember https://developer.android.com/jetpack/compose/state#state-in-composables它。双括号 ({{ }}) 在这里至关重要,因为您需要记住 lambda。

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

我知道它看起来有点奇怪,你可以使用rememberLambda https://gist.github.com/PhilipDukhov/949629d5a45fe524707ee02b55e0338d这将使您的代码更具可读性:

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

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


一般来说,重组并不是一件坏事。当然,如果您可以减少它,您应该这样做,但是即使您的代码被重组很多​​次,它也应该可以正常工作。例如,您不应该在可组合项内部进行大量计算来执行此操作,而是使用副作用 https://developer.android.com/jetpack/compose/side-effects.

所以如果重新组合Clock导致奇怪的 UI 效果,可能是你的有问题NumberClock无法在重组中幸存下来。如果是这样,请添加NumberClock针对您的问题编写代码以获取有关如何改进它的建议。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么在回调中调用 ViewModel 时会发生重组? 的相关文章

  • 决策树和规则引擎 (Drools)

    In the application that I m working on right now I need to periodically check eligibility of tens of thousands of object
  • WCF 服务主机配置 - 请尝试将 HTTP 端口更改为 8732

    我的 PC 上运行着一个复杂的基于 WCF 服务的解决方案 但由于安装 Windows 8 1 时出现问题 我不得不 刷新 我的 PC 现在我已经重新安装了 Visual Studio 2012 我的项目不再正常运行 当我调试单元测试时 w
  • Java中单例的其他方式[重复]

    这个问题在这里已经有答案了 只是我在考虑编写单例类的其他方法 那么这个类是否被认为是单例类呢 public class MyClass static Myclass myclass static myclass new MyClass pr
  • Spark scala 模拟 Spark.implicits 用于单元测试

    当尝试使用 Spark 和 Scala 简化单元测试时 我使用 scala test 和mockito scala 以及mockito Sugar 这只是让你做这样的事情 val sparkSessionMock mock SparkSes
  • Chrome 调试器注入 javascript

    我有这样的好奇心 是否可以以某种方式在我的页面中注入 javascript 并执行它并调试它 正如您在控制台中所做的那样 但在控制台中您无法暂停并观察变量 是否可以调试我通过控制台输入的代码 为什么无法调试通过 XHR 接收的代码 Than
  • Matplotlib loglog 的错误刻度/标签(双轴)

    我正在使用 matplotlib 创建对数图 如下图所示 默认刻度选择得很糟糕 充其量是这样 右边的 y 轴甚至根本没有 在线性等效中确实如此 而两个 x 轴都只有一个 有没有办法获得合理数量的带有标签的刻度 without为每个情节手动指
  • 区分 NaN 输入和输入类型为“number”的空输入

    我想使用 type number 的表单输入 并且只允许输入数字
  • 如何将 SQLite 数据库捆绑到 Go 二进制文件中?

    我尝试使用 go bindata 和 packr 但这些包没有显示如何将 SQLite 数据库文件打包到二进制文件中 我不需要以任何方式更新数据库 我只想在启动时从中读取数据 如何将 SQLite 数据库文件嵌入到 Go 二进制文件中 SQ
  • 在DialogFragment中,onCreate应该做什么?

    我目前正在摆弄 DialogFragment 以学习使用它 我假设相比onCreateView onCreate 可以这样做 public void onCreate Bundle savedInstanceState super onCr
  • 使用溢出支持定位粘性填充材料[重复]

    这个问题在这里已经有答案了 我在用position sticky在我的应用程序中 在使用overflow属性来显示滚动条 我已经寻找了一个确实支持这种情况的polyfill 但到目前为止没有任何运气 有谁知道这样的polyfill shim
  • 如何禁用 solr 管理页面

    对于生产来说 拥有一个甚至不要求登录凭据的 solr 管理员感觉不安全 如何禁用默认的 solr 管理页面 我只是希望我的 web 应用程序使用 Solr 进行搜索词索引 我强烈建议保留管理页面用于调试目的 它在很多情况下拯救了我 有多种方
  • 进程被杀死后不会调用 onActivityResult

    我有一个主要活动 Main 和另一个活动 Sub 由 Main 调用 startActivityForResult new Intent this SubActivity class 25 当我在 Sub 时 我终止该进程 使用任务管理器或
  • 在成为FirstResponder或resignFirstResponder的情况下将对象保持在键盘顶部?

    我目前在键盘顶部有一个 UITextField 当您点击它时 它应该粘在键盘顶部并平滑地向上移动 我不知道键盘的具体时长和动画类型 所以确实很坎坷 这是我所拥有的 theTextView resignFirstResponder UIVie
  • 水平和垂直居中 div 位于页面中间,页眉和页脚粘在页面顶部和底部

    我正在尝试制作一个具有固定高度页眉和页脚的页面 页眉位于屏幕顶部 100 宽度 页脚位于底部 100 宽度 我想将一个具有可变高度内容的 div 居中放置在页眉和页脚之间的空间中 在下面的 jsfiddle 中 如果内容比空格短 它会起作用
  • 是否可以使用 Dapper 流式传输大型 SQL Server 数据库结果集?

    我需要从数据库返回大约 500K 行 请不要问为什么 然后 我需要将这些结果保存为 XML 更紧急 并将该文件通过 ftp 传输到某个神奇的地方 我还需要转换结果集中的每一行 现在 这就是我正在做的事情 TOP 100结果 使用 Dappe
  • 描述符“join”需要“unicode”对象,但收到“str”

    代码改编自here http wiki geany org howtos convert camelcase from foo bar to Foo Bar def lower case underscore to camel case s
  • 使用 paramiko 运行 Sudo 命令

    我正在尝试执行sudo使用 python paramiko 在远程计算机上运行命令 我尝试了这段代码 import paramiko ssh paramiko SSHClient ssh set missing host key polic
  • 对象指针值作为字典的键

    我想使用对象的引用值作为字典的键 而不是对象值的副本 因此 我本质上想在字典中存储与另一个对象的特定实例关联的对象 并稍后检索该值 这可能吗 是不是完全违背了NSDictionary的理念 我可以看出我可能以错误的方式处理这个问题 因为字典
  • 为什么 try catch 块没有捕获 Promise 异常?

    我对承诺的错误处理感到困惑 答案可能很明显 但我不明白 我有以下示例代码 var test async function throw new Error Just another error try test then catch err
  • R data.table 1.9.2 关于 setkey 的问题

    这似乎是 1 8 10 后引入的一个错误 与包含列表的 DT 的 setkey 相关 运行下面两个代码来查看问题 library data table dtl lt list dtl 1 lt data table scenario 1 p

随机推荐