fin*_*usl 2 android event-driven android-livedata android-jetpack
问题介绍:
在使用MediatorLiveDataandroid自带的android jetpack的时候,我发现自己经常从各个源调用同一个函数。例如,这可能是因为,每当更新一个来源时,我都必须检查它是否有影响,或者另一个来源是否更重要。代码示例(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
}
Run Code Online (Sandbox Code Playgroud)
悬停时项目为绿色,选中时为红色,未悬停时为红色,否则为灰色。当 isSelected 变为 true 时,在将颜色更改为红色之前,我还需要检查它是否处于悬停状态。此外,当 isHovering 更改为 false 时,我需要在将颜色更改为灰色之前检查它是否被选中。所以最简单的是一个函数,它考虑了所有变量并相应地设置颜色。
我的问题:
当 MediatorLiveData 从非活动状态变为活动状态时,因为视图移到了前台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() }
}
Run Code Online (Sandbox Code Playgroud)
然后我创建了一个扩展函数来只发出不同的值
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
因此,在观察state.distinct()时,只有当它真正发生变化时,您才会获得更新的值。
有时另一个扩展也很有用:
fun <T> LiveData<T>.squashUpdates() = MediatorLiveData<T>().apply {
addSource(this@squashUpdates) {
postValue(it)
}
}
Run Code Online (Sandbox Code Playgroud)
通常,当LiveDatavalue 更改时,它会立即通知同一堆栈帧中的所有观察者。假设您有MediatorLiveData多个来源的a和更改值,例如:
isHovered.value = true
isSelected.value = true
Run Code Online (Sandbox Code Playgroud)
state值将连续更改两次State(true, false)并且State(true, true). 即使distinct从上面使用,它们也会被调度,因为值实际上是不同的。squashUpdates在这种情况下,通过将调度延迟到堆栈帧的末尾,仅调度最后一个值来提供帮助。
| 归档时间: |
|
| 查看次数: |
2863 次 |
| 最近记录: |