[Android] Plaid App 中的 LiveData 混淆

LiveData confusion in [Android] Plaid App

我指的是 github Link to Plaid

上的 Plaid 开源项目

它是在 Android 上学习新技术的绝佳来源。

当我浏览代码时,我发现了围绕 LiveData 的某种编码风格,我真的不明白。如果有人可以帮助我得到它。 这里是:

这段代码有一个ViewModel(vm)

private val _openLink = MutableLiveData<Event<String>>()
val openLink: LiveData<Event<String>>
    get() = _openLink

还算简单?请注意,这里有 2 个变量:openLink_openLinkopenLink 的 getter 正在返回 _openLink LiveData。

在 activity 他们观察 openLink LiveData 如下:

viewModel.also { vm ->

       vm.openLink.observe(this, EventObserver { openLink(it) })

        ..... // Other stuff
}

现在,另一个实时数据 _openLink 被 UI 调用,据说是在单击按钮时调用的,它的定义如下:

fun viewShotRequested() {
    _shotUiModel.value?.let { model -> // ignore this part
        _openLink.value = Event(model.url) // setValue on _openLink
    }
}

所以我的理解是,在 setValue()_openLink 上,EventObserver{openLink(it)} 将被调用。 我的问题是,他们为什么要这样做?

问题:

  1. 为什么不在 _openLink 上直接观察

  2. 会不会有同样的效果?我在这里错过了什么?

_openLink 是可变的。你必须始终暴露一些不可变的东西,并且不能被你的观察者改变,因为那只能由你的 ViewModel 完成,即使暴露 _openLink 没有任何效果。

这就是为什么您需要公开不可变的 openLink

private val _openLink = MutableLiveData<Event<String>>()
val openLink: LiveData<Event<String>> = _openLink

不应公开 MutableLiveData 属性:它是可变的,可以在程序的任何位置更改。
这就是 LiveData 被公开的原因:它负责更新您的 属性,并使用 MutableLiveData 作为支持字段。
例外情况是双向数据绑定,其中需要直接访问值。

My question is, why have they done it like this?

因为Google显然喜欢为了写更多的代码而写更多的代码。

如果你倾向于相信他们的话,假设的答案是LiveData<Event<T>> is preferred over SingleLiveData because they came up with it later than with LiveData<Event<T>> and is therefore supposedly better

他们打算使用 "enqueueable event-bus that forgets items after it is emitted to at least 1 observer",但 Jetpack 没有提供开箱即用的概念,就个人而言 I had to write one of my own

即便如此,您是否可以写入某物与您是否只能从某物读取而不能自己写入之间是有区别的。在这种情况下,只有 ViewModel 希望能够发出事件,因此是持有 Mutable__ 引用的 ViewModel,但向外界公开常规 LiveData(在我的例子中,EventEmitter 对比 EventSource).

至于 _,这是一种 Kotlin 风格的约定,希望有一天会有所改变,您可以这样做:

private val _openLink = MutableLiveData<Event<String>>()
val openLink: LiveData<Event<String>>
    get() = _openLink

不过你也可以

private val openLink = MutableLiveData<Event<String>>()
fun openLink(): LiveData<Event<String>> = openLink

这样我们就可以在自己的代码中放弃 _ 前缀,但出于某种原因,Kotlin 的作者没有及时提出该约定。