我正在使用 ViewModel
在我的 Android 应用程序中设置一个 MVVM 模式来自 Android 的类。
现在我需要从我的 ViewModel
发送事件(最终带有数据)到 Fragment
.
以前我和我的同事使用 rx Subject
在ViewModel
这样 Fragment
可以观察它并触发导航或其他Fragment
-收到新元素时的特定元素。项目通常包含在字符串或枚举元素中。请注意,我们处理了 Observer
的处理在onDestroy
我们 fragment 的方法。
现在我们可以简单地设置一个 Observer
对于 MutableLiveData
ViewModel
的领域几乎与我们处理 rx Observer
的方式相同.此外,Android 应自动处理 Observer
的处理/更新。在 Fragment
内生命周期。
所有这些都是因为 Android 警告不要保留对 Fragment
的引用而设置的在ViewModel
里面为了避免 Fragment
的陈旧实例发生内存泄漏不在 gc 中,因为在幸存的 ViewModel
中仍被引用.
我实际上不太喜欢这种方法,因为在我看来让一些可观察字段发出字符串或枚举项有几个问题:
- 并不是很清楚每个 strng/enum 项目应该触发什么。您可以为它们提供可读的提示值/名称,但无论如何它都不像具有适当文档字符串的方法名称
- 您可以在
Bundles
中发送额外的参数,但它不像类型等的正确方法签名。
所以基本上我宁愿使用接口(interface)并设置/取消设置处理程序,也不愿观察字段。
所以现在我的 fragment 中有
viewModel.observe(this, Observer {
when(it.event) {
"I did This" -> handleViewModelDidThis(it.bundle),
"I did That" -> handleViewModelDidThat(it.bundle)
}
})
虽然我想要的是 ViewModelEventsHandler
界面如:
interface ViewModelEventsHandler {
/**
* Handle the fact that the ViewModel did this.
* @parameter how How the ViewModel did this
* @parameter when When did the ViewModel do this
*/
fun viewModelDidThis(String how, Date when)
/**
* Handle the fact that the ViewModel did that.
* @parameter where Where did the ViewModel do that
* @parameter withWho Who was with him when he did that
*/
fun viewModelDidThis(Location where, List<Friends> withWho)
}
然后在 Fragment
viewModel.eventsHandler = ViewModelEventsHandler {
override fun viewModelDidThis(String how, Date when) {
handleViewModelDidThis(how, when)
}
override fun viewModelDidThis(Location where, List<Friends> withWho) {
handleViewModelDidThat(where, withWho)
}
}
所以我的问题是:假设在这两种情况下我都注册了一个匿名类,该类引用了我的 Fragment
中的方法。 (第一个是Observer
,第二个是我的ViewModelEventsHandler
)有什么不同使得Observer
在 Fragment
方面“更安全”实例保留还是它们的行为相同?如果有任何区别,我如何设置适当的回调/处理程序来专门解决可能的问题 ViewModel
事件而不是在实时字段上监听“不安全”值?
谢谢
最佳答案
您需要记住的一个关键区别是 LiveData
知道观察者何时附加到它,并且如果 LiveData
准备就绪,可以立即发出一个值。例如,如果您的 View 由于某些配置更改而分离并重新附加到同一个 ViewModel,LiveData
可以立即发出一个值,因此您的 View 可以无缝地恢复状态。您不能通过接口(interface)执行此操作,您可以通过接口(interface)执行的最佳操作是在每次调用处理程序时检查处理程序是否为空,以防止应用程序崩溃。
还有你的两点:
- It's not really clear what each strng / enum item should trigger. You can give them readable hinting values/names, but it's not like a method name with proper docstrings anyway
- You could send additional arguments in Bundles, but it's not like proper method signature with types etc.
是正确的,除了 RxJava
和 LiveData
都可以轻松处理这些问题,因为它们是设计问题,而不是工具问题。例如,您的 Event
类可能如下所示:
class Event(event: String, data: Bundle)
不要这样做。更好的做法:
abstract class Event()
class DoneThisEvent(how:How, when:Time): Event()
class DoneThatEvent(location:Location, withWho:Person): Event()
此外,您应该考虑事件之间的依赖关系。换句话说,“我做了这个”事件和“我做了那个”事件可以同时存在吗?比较给定的 LiveData
实现和 ViewModelEventsHandler
实现是不公平的,因为在 LiveData
实现中,这表明这两个事件不能共存,而在ViewModelEventsHandler
实现,他们可以。让我们比较一下这两种情况:
如果两个事件不能共存
那么您的 LiveData
示例就有意义了,但仍有改进的余地:
viewModel.iDidThisAndThat.observe(this, Observer { done ->
when(done) {
is DoneThisEvent -> handleViewModelDidThis(done.how, done.when) // Notice the automatic type casting
is DoneThatEvent -> handleViewModelDidThat(done.location, done.withWho)
}
})
同时检查你的 ViewModelEventsHandler
副本。
viewModel.eventsHandler = ViewModelEventsHandler {
override fun viewModelDidThisAndThat(done: Event) {
when(done) {
is DoneThisEvent -> handleViewModelDidThis(done.how, done.when) // Notice the automatic type casting
is DoneThatEvent -> handleViewModelDidThat(done.location, done.withWho)
}
}
}
如您所见,它们之间没有区别,只是使用 ViewModelEventsHandler
您需要手动进行 null 检查并处理附加/分离事件处理程序。
如果两个事件可以共存
如果两个事件是独立的,那么它们必须被独立观察。
// In activity onCreate
viewModel.iDidThis.observe(this, Observer { doneThis ->
handleViewModelDidThis(doneThis.how, doneThis.when)
})
viewModel.iDidThat.observe(this, Observer { doneThat ->
handleViewModelDidThat(doneThat.location, doneThat.withWho)
}
// In your ViewModel
val iDidThis: LiveData<DoneThisEvent>
val iDidThat: LiveData<DoneThatEvent>
这个 LiveData
实现不应该比它的 ViewModelEventsHandler
对应物看起来更难看或更难管理:
viewModel.eventsHandler = ViewModelEventsHandler {
override fun viewModelDidThis(String how, Date when) {
handleViewModelDidThis(how, when)
}
override fun viewModelDidThis(Location where, List<Friends> withWho) {
handleViewModelDidThat(where, withWho)
}
}
关于java - 注册观察者与设置处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55965962/