【问题标题】:Why is a wrapper necessary for a LiveData value?为什么 LiveData 值需要包装器?
【发布时间】:2022-01-20 16:45:48
【问题描述】:

我查看了JetSurvey project(Android Jetpack Compose 示例项目)并注意到他们创建了一个类来将 LiveData 值包装在他们的 ViewModel 类中。这是我正在谈论的课程:

/**
 * Used as a wrapper for data that is exposed via a LiveData that represents an event.
 */
data class Event<out T>(private val content: T) {

    var hasBeenHandled = false
        private set // Allow external read but not write

    /**
     * Returns the content and prevents its use again.
     */
    fun getContentIfNotHandled(): T? {
        return if (hasBeenHandled) {
            null
        } else {
            hasBeenHandled = true
            content
        }
    }

    /**
     * Returns the content, even if it's already been handled.
     */
    fun peekContent(): T = content
}

在 ViewModel 中,这是这样使用的:

private val _navigateTo = MutableLiveData<Event<Screen>>()
    val navigateTo: LiveData<Event<Screen>> = _navigateTo

fun signInAsGuest() {
        _navigateTo.value = Event(Survey)
    }

似乎 Event 类的目的是避免多次发生导航。但是,我不明白这首先会如何发生,因为只有在 LiveData 值更新后才会触发导航。并且每次更新值时,都会创建一个新的 Event 对象,因此它会再次运行。

那么在 Fragment 中,viewModel.navigateTo.observe(viewLifecycleOwner) 中的代码是否有可能在没有更新值的情况下多次运行?如果是这样,在什么情况下会发生这种情况?

如果我对 Event wrapper 角色的理解不正确,那么它的实现目的是什么?有必要吗?

【问题讨论】:

    标签: android kotlin mvvm observable android-livedata


    【解决方案1】:

    假设您在 Fragment 中的 LiveData 观察者导航到第二个 Fragment。用户旋转屏幕,第一个 Fragment 实例被销毁。当他们退出第二个 Fragment 时,会重新创建第一个 Fragment 的新实例,因此再次触发其观察者。如果没有事件包装器,它会突然出人意料地立即导航回第二个 Fragment。

    另外,一个 LiveData 可能有多个观察者。也许两个不​​同的 Fragment 正在观察相同的事件 LiveData,但您不想冒险为同一事件向用户显示两次消息。例如,他们可以导航到与第一个 Fragment 观察相同事件 LiveData 的第二个 Fragment。一个事件触发,第二个 Fragment 观察者向用户显示一个对话框或其他东西。然后用户备份到第一个 Fragment,相同的事件将触发第一个 Fragment 的观察者,因此该事件被处理两次。

    如果您的项目使用协程,则此事件观察问题的更简洁的解决方案是使用 replay 为 0 的 SharedFlow,而不是使用带有事件包装类的 LiveData。我怀疑他们没有在 JetSurvey 项目中使用 SharedFlow 的原因是他们不想假设您已经熟悉 Flows,而这不是示例的内容。

    一个名为 SingleLiveEvent 的替代解决方案曾经出现在一个官方 Android 示例中,but was considered too hacky to add to the Jetpack libraries

    【讨论】:

      猜你喜欢
      • 2011-01-09
      • 2014-06-25
      • 1970-01-01
      • 1970-01-01
      • 2018-01-02
      • 2013-10-01
      • 2018-11-20
      • 2015-01-16
      相关资源
      最近更新 更多