java - 注册观察者与设置处理程序

标签 java android rx-java android-livedata android-viewmodel

我正在使用 ViewModel 在我的 Android 应用程序中设置一个 MVVM 模式来自 Android 的类。

现在我需要从我的 ViewModel 发送事件(最终带有数据)到 Fragment .

以前我和我的同事使用 rx SubjectViewModel这样 Fragment可以观察它并触发导航或其他Fragment -收到新元素时的特定元素。项目通常包含在字符串或枚举元素中。请注意,我们处理了 Observer 的处理在onDestroy我们 fragment 的方法。

现在我们可以简单地设置一个 Observer对于 MutableLiveData ViewModel 的领域几乎与我们处理 rx Observer 的方式相同.此外,Android 应自动处理 Observer 的处理/更新。在 Fragment 内生命周期。

所有这些都是因为 Android 警告不要保留对 Fragment 的引用而设置的在ViewModel里面为了避免 Fragment 的陈旧实例发生内存泄漏不在 gc 中,因为在幸存的 ViewModel 中仍被引用.

我实际上不太喜欢这种方法,因为在我看来让一些可观察字段发出字符串或枚举项有几个问题:

  1. 并不是很清楚每个 strng/enum 项目应该触发什么。您可以为它们提供可读的提示值/名称,但无论如何它都不像具有适当文档字符串的方法名称
  2. 您可以在 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)有什么不同使得ObserverFragment 方面“更安全”实例保留还是它们的行为相同?如果有任何区别,我如何设置适当的回调/处理程序来专门解决可能的问题 ViewModel事件而不是在实时字段上监听“不安全”值?

谢谢

最佳答案

您需要记住的一个关键区别是 LiveData 知道观察者何时附加到它,并且如果 LiveData 准备就绪,可以立即发出一个值。例如,如果您的 View 由于某些配置更改而分离并重新附加到同一个 ViewModel,LiveData 可以立即发出一个值,因此您的 View 可以无缝地恢复状态。您不能通过接口(interface)执行此操作,您可以通过接口(interface)执行的最佳操作是在每次调用处理程序时检查处理程序是否为空,以防止应用程序崩溃。

还有你的两点:

  1. 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
  2. You could send additional arguments in Bundles, but it's not like proper method signature with types etc.

是正确的,除了 RxJavaLiveData 都可以轻松处理这些问题,因为它们是设计问题,而不是工具问题。例如,您的 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/

相关文章:

java - 如何测试java DBMS应用程序的性能

android - 在android中将位图转换为jpeg

java - 无法导入SDK DJI android

java - FragmentManager 无法在 androidx 中解析

java - android - 带有 HashMap 的 ListView 适配器显示不正确

rx-java - 在 RxJava 中,我无法从 flatMap 发出 onComplete

rx-java - 具有超过九个参数的 RxJava 函数

rx-java - RxJava2 TestObserver类-getOnNextEvent与TestSubscriber类相似的地方在哪里?

java - 如何检查文件名是否已经存在?

使用循环和跳转语句的 Java 程序