为什么调用两次时Livedata setValue会被忽略?
Why is Livedata setValue ignored when called twice?
我有以下带有 MutableLiveData data
和另一个从 data
派生的 LiveData ones
的 ViewModel,它仅在 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
是空的,我该如何解决这个问题?
也许我遗漏了什么,但这种行为似乎符合我的预期...
让我们尝试按顺序重现这两种情况。
没有 doSomething() :
- 创建
Livedata
- 添加
Dummy(1, "Init")
- 开始在片段中收听:因为数字是
1
,它通过了您的过滤器并且片段接收到它
用 doSomething():
- 创建
Livedata
- 添加
Dummy(1, "Init")
- 添加
Dummy(2, "Do something")
(LiveData
只保留最后一个值,所以如果没有人观察,第一个值就会丢失)
- 开始在片段中监听:因为数字是
2
,值被过滤,片段什么也接收不到
一点题外话:像这样为 ViewModel 案例编写测试总是好的,因为您将能够隔离问题并快速找到真正的原因。
编辑:另请注意,您的过滤器仅用于观察,在将值放入 LiveData
时不会应用它。
我有以下带有 MutableLiveData data
和另一个从 data
派生的 LiveData ones
的 ViewModel,它仅在 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
是空的,我该如何解决这个问题?
也许我遗漏了什么,但这种行为似乎符合我的预期...
让我们尝试按顺序重现这两种情况。
没有 doSomething() :
- 创建
Livedata
- 添加
Dummy(1, "Init")
- 开始在片段中收听:因为数字是
1
,它通过了您的过滤器并且片段接收到它
用 doSomething():
- 创建
Livedata
- 添加
Dummy(1, "Init")
- 添加
Dummy(2, "Do something")
(LiveData
只保留最后一个值,所以如果没有人观察,第一个值就会丢失) - 开始在片段中监听:因为数字是
2
,值被过滤,片段什么也接收不到
一点题外话:像这样为 ViewModel 案例编写测试总是好的,因为您将能够隔离问题并快速找到真正的原因。
编辑:另请注意,您的过滤器仅用于观察,在将值放入 LiveData
时不会应用它。