【问题标题】:Why is Livedata setValue ignored when called twice?为什么 Livedata setValue 在调用两次时会被忽略?
【发布时间】:2020-04-04 18:08:18
【问题描述】:

我有以下 ViewModel 与 MutableLiveData data 和另一个 LiveData ones 派生自data,只有当 data.number 等于 1 时它才会更新其值。

class DummyViewModel : ViewModel() {

    private val data = MutableLiveData<Dummy>()
    val ones = data.mapNotNull { it.takeIf { it.number == 1 } }

    init {
        data.value = Dummy(1, "Init")
        doSomething()

    }

    fun doSomething() {
        data.value = Dummy(2, "Do something")
    }
}

data class Dummy(val number: Int, val text: String)

fun <T, Y> LiveData<T>.mapNotNull(mapper: (T) -> Y?): LiveData<Y> {
    val mediator = MediatorLiveData<Y>()
    mediator.addSource(this) { item ->
        val mapped = mapper(item)
        if (mapped != null) {
            mediator.value = mapped
        }
    }
    return mediator
}

我在片段中观察到ones。但是,如果我执行doSomething,我的片段中不会收到任何更新。如果我不执行doSomething,虚拟Init 会正确出现在ones 中,并且我会收到更新。

这里发生了什么?为什么ones 为空,我该如何解决这个问题?

【问题讨论】:

  • 你对这个it.takeIf { it.number == 1 }有什么期待?
  • @StanislavBondar 我希望 ones LiveData 仅在对象的 number 属性为 1 时更新其值。这当然只是为了演示目的。
  • @StanislavBondar 令我吃惊的问题是,如果调用doSomething,则不会设置第一个data.value = Dummy(1, "Init")

标签: android kotlin android-livedata android-jetpack android-viewmodel


【解决方案1】:

也许我遗漏了一些东西,但这种行为对我来说似乎是预期的......

让我们尝试依次重现这两种情况。

没有 doSomething() :

  1. 创建Livedata
  2. 添加Dummy(1, "Init")
  3. 在片段中开始监听:因为号码是1,它通过了你的过滤器,片段接收到它

使用 doSomething():

  1. 创建Livedata
  2. 添加Dummy(1, "Init")
  3. 添加Dummy(2, "Do something")LiveData只保留最后一个值,所以如果没有人观察,第一个值会丢失)
  4. 开始在片段中监听:因为数字是2,所以值被过滤,片段没有收到任何东西

有点离题:为这样的 ViewModel 案例编写测试总是好的,因为您将能够隔离问题并快速找到真正的原因。

编辑:还请注意,您的过滤器仅用于观察,将值放入 LiveData 时不会应用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-24
    • 2017-05-26
    相关资源
    最近更新 更多