问题简介:
当使用 android 随 android jetpack 添加的 MediatorLiveData
时,我发现自己经常从各个来源调用相同的函数。例如,这可能是因为,每当更新源时,我都必须检查它是否有影响,或者另一个源是否更重要。代码示例(Kotlin,但不重要):
val isHovered = MutableLiveData<Boolean>()
val isSelected = MutableLiveData<Boolean>()
val color = MediatorLiveData<Int>().apply {
addSource(isHovered) { updateColor() }
addSource(isSelected) { updateColor() }
}
fun updateColor() {
if (isHovered.value == true)
color.value = Color.GREEN
else if (isSelected.value == true)
color.value = Color.RED
else
color.value = Color.GRAY
}
项目悬停时为绿色,选择且未悬停时为红色,否则为灰色。当 isSelected 更改为 true 时,在将颜色更改为红色之前,我仍然需要检查它是否悬停。另外,当 isHovering 更改为 false 时,我需要在将颜色更改为灰色之前检查它是否被选中。因此,最简单的是一个函数,它考虑所有变量并相应地设置颜色。
我的问题:
当 MediatorLiveData 从非 Activity 状态更改为 Activity 状态时,由于 View 移至前台,因此可能会针对每个发生更改的源多次调用函数 updateColor
。这是不必要的,因为每次调用都已经考虑了所有变量。由于此函数可能非常复杂并且可能有很多源,有没有办法避免对源 LiveDatas 的相同状态多次调用它?
最佳答案
我遇到了同样的问题并提出了以下解决方案。首先,将所有来源的值收集到一个值:
data class State(val isHovered: Boolean, val isSelected: Boolean)
private val state = MediatorLiveData<State>().apply {
fun update() {
value = State(isHovered.value ?: false, isSelected.value ?: false)
}
addSource(isHovered) { update() }
addSource(isSelected) { update() }
}
然后我创建了一个扩展函数来仅发出不同的值
fun <T> LiveData<T>.distinct(): LiveData<T> = MediatorLiveData<T>().apply {
var wasSet = false
addSource(this@distinct) {
// Update value if it has been changed or it's the first time the method called
// Because value is null by default it will not be set to null again, leaving the live data in [value not set] state
if (value != it || !wasSet) {
value = it
wasSet = true
}
}
}
因此,当观察 state.distinct()
时,只有当它真正发生变化时,您才会获得更新的值。
有时另一个扩展也可能有用:
fun <T> LiveData<T>.squashUpdates() = MediatorLiveData<T>().apply {
addSource(this@squashUpdates) {
postValue(it)
}
}
通常,当 LiveData 值发生更改时,它会立即通知同一堆栈帧中的所有观察者。假设您有一个 MediatorLiveData
并更改多个源的值,例如:
isHovered.value = true
isSelected.value = true
state
值将连续改变两次State(true, false)
和State(true, true)
。即使使用上面的 distinct
,它们都会被调度,因为值实际上是不同的。在这种情况下,squashUpdates
通过延迟调度到堆栈帧的末尾、仅调度最后一个值来提供帮助。
关于android - 如何避免 MediatorLiveData 的所有源调用同一函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57256018/