android - 如何使用 SingleLiveEvent 类将多个命令从 MVVM 发送到视图
问题描述
我的 android 应用程序中有一个 ViewModel,它有一些逻辑,并且视图需要根据该逻辑的结果进行调整/执行不同的事情。起初我试图只用观察者来做这件事,并对视图模型中的数据状态做出反应,但这太复杂了。
然后我发现了使用 SingleLiveEvent 类的命令的概念,我发现它很好,因为它让我想起了使用 Xamarin 和微软的 mvvvm 时相同的模式。与 xamarin 一起工作的(少数)好事之一;)
好吧,我的问题是,当我有多个命令需要发送到视图时,视图只接收一个命令。有时是最后一个,有时是第一个。例如,命令视图执行复杂操作的几个命令:
sealed class CustomCommands{
class CustomCommand1 : CustomCommands()
class CustomCommand2() : CustomCommands()
class CustomCommand3() : CustomCommands()
class CustomCommand4() : CustomCommands()
class CustomCommand5() : CustomCommands()
}
然后在我的 viewModel 中,我有命令 SingleLiveEvent 对象:
class CustomViewModel...{
val commands: SingleLiveEvent<CustomCommands> = SingleLiveEvent()
private fun doComplicatedThingsOnTheUI() {
GlobalScope.launch(Dispatchers.IO) {
if (someConditionsInvolvingRestRequestsAndDatabaseOperations()){
commands.postValue(CustomCommands.CustomCommand1())
commands.postValue(CustomCommands.CustomCommand2())
} else {
commands.postValue(CustomCommands.CustomCommand3())
commands.postValue(CustomCommands.CustomCommand4())
}
commands.postValue(CustomCommands.CustomCommand5())
}
}
}
在活动/片段中,我有命令的观察者,它应该对每个命令做出反应并完成工作:
class MainActivity...{
viewModel.commands.observe(this, Observer { command ->
Rlog.d("SingleLiveEvent", "Observer received event: " + command.javaClass.simpleName)
when (command) {
Command1->doSomething1()
Command2->doSomething2()
}
}
好吧,问题是视图通常只接收最后一个命令(Command5)。但行为取决于 Android SDK 的 api 级别。通过 api 16,视图接收到最后一个命令。通过 Api 28,视图通常接收第一个和最后一个命令(例如,Command1 和 Command5,但不是 Command2)。
也许我理解 SingleLiveEvent 类的功能是错误的,或者整个 Command 的事情是错误的,但我需要一种方法来允许视图模型根据许多对象和变量的状态命令视图执行某些操作。上面的代码只是一个示例,实际情况比这更复杂。
我不想在视图模型和视图之间使用回调,因为我在某处读到了破坏整个 MVVM 模式的地方。
也许有人对我有建议。欢迎任何帮助。
先感谢您。
解决方案
我想我找到了一种解决方法,它似乎有效(我只测试了几个小时)。
问题是我正在使用“command.postValue(XXX)”,因为那段代码在一个 couroutine 中运行,即在其他线程中。因此,我不能直接使用 command.value 。
但事实是,使用 command.value=Command1(),它可以工作。我的意思是,视图接收所有发送的命令,而且非常重要,它们的顺序与发送的顺序相同。因此,我编写了一个小函数来将命令发送到切换线程的 UI。
我不确定这是否正确,我是 Kotlin 协程的新手,我不得不承认我还不太了解它们:
private suspend fun sendCommandToView(vararg icommands: CustomCommands) = withContext(Dispatchers.Main) {
icommands.forEach {
commands.value = it
}
}
然后我发送命令
sendCommandToView(CustomCommand1(),CustomCommand2(),CustomCommand5())
这似乎有效。认为“发布”方法会以类似的方式工作,但事实并非如此。
问候。
推荐阅读
- javascript - 将整数列表发送到 REST API 会引发 415(不支持的媒体类型)
- python - 错误:对象可以在同一个线程中使用
- javascript - 在 2 个 svg rects 之间绘制动态线
- django - Django - 在管理员工作中显示历史记录,但仅在管理员中发生操作时显示
- javascript - 为什么我的函数不会绘制多个砖块?
- r - 如何计算R中多年的每个月的中位数?
- arduino - Arduino 获取请求导致 FastAPI 无效 HTTP 请求
- loops - 基本while循环的断言错误/异常
- ruby-on-rails - Rails - 包含一个模块而不使用包含这个词
- mysql - 使用 node.js MySQL 连接 ECONNREFUSED 仍然出现错误