Android 如何避免MediatorLiveData的所有源调用同一个函数?
问题介绍: 当使用android随android jetpack添加的Android 如何避免MediatorLiveData的所有源调用同一个函数?,android,android-livedata,android-jetpack,event-driven,Android,Android Livedata,Android Jetpack,Event Driven,问题介绍: 当使用android随android jetpack添加的MediatorLiveData时,我发现自己经常从每个源调用相同的函数。例如,这可能是因为,每当更新一个源时,我必须检查它是否有影响,或者另一个源是否更重要。代码中的示例(Kotlin,但不重要): val isHovered=MutableLiveData() val isSelected=MutableLiveData() val color=MediatorLiveData()。应用{ addSource(isHove
MediatorLiveData
时,我发现自己经常从每个源调用相同的函数。例如,这可能是因为,每当更新一个源时,我必须检查它是否有影响,或者另一个源是否更重要。代码中的示例(Kotlin,但不重要):
val isHovered=MutableLiveData()
val isSelected=MutableLiveData()
val color=MediatorLiveData()。应用{
addSource(isHovered){updateColor()}
addSource(isSelected){updateColor()}
}
有趣的更新颜色(){
如果(isHovered.value==true)
color.value=color.GREEN
else if(isSelected.value==true)
color.value=color.RED
其他的
color.value=color.GRAY
}
悬停时该项目为绿色,选中且未悬停时为红色,否则为灰色。当isSelected更改为true时,我仍然需要检查它是否悬停,然后再将颜色更改为红色。此外,当iOvering更改为false时,我需要在将颜色更改为灰色之前检查是否选中它。因此,最简单的是一个函数,它将所有变量都考虑在内,并相应地设置颜色
我的问题:
当MediaLiveData从非活动变为活动时,由于视图被移动到前台,可能会对每个更改的源多次调用函数
updateColor
。这是不必要的,因为每个调用已经考虑了所有变量。由于此函数可能非常复杂,并且可能有许多源,有没有办法避免对源LiveData的相同状态多次调用它?要避免多次调用,您应该只从LiveData
实例发送新的更新。要实现这一点,可以使用SingleLiveEvent
:
一个生命周期感知的可观察对象,在
订阅,用于导航和Snackbar消息等事件
这避免了事件的一个常见问题:配置更改
(如旋转)如果观察者处于活动状态,则可以发出更新。这
LiveData仅在显式调用
setValue()或call()
请注意,只有一个观察者会收到更改通知
您可能无法阻止
IsOvered
或isSelected
发射项目,但您可以阻止color
发射多个相同类型的项目。其思想是仅当当前颜色不等于新颜色时才更改颜色
fun updateColor() {
var newColor: Color?
if (isHovered.value == true)
newColor = Color.GREEN
else if (isSelected.value == true)
newColor = Color.RED
else
newColor = Color.GRAY
if (color.value != newColor) {
color.value = newColor!!
}
}
我也遇到了同样的问题,并提出了以下解决方案。首先,将所有来源的值收集到一个值:
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() }
}
通常,当更改LiveData
值时,它会立即通知同一堆栈帧中的所有观察者。假设您有一个中介livedata
,并更改多个源的值,如:
isHovered.value = true
isSelected.value = true
状态
值将在一行中更改两次状态(真、假)
和状态(真、真)
。它们都将被分派,即使使用上面的distinct
,因为值实际上是不同的squashUpdates
在这种情况下有助于将调度延迟到堆栈帧的末尾,仅调度最后一个值 SingleLiveEvent是我正在使用的一种模式,但是如果所有源LiveData都有新的值,它就不起作用。公共函数仍然会被频繁调用。我明白了。我已经有了一个助手函数,它只在实际更改时更新。但这并不能阻止昂贵的函数运行两次为什么需要apply
函数?@IgorGanapolsky这是一个Kotlin的东西,允许我直接使用对象,同时返回它。您也可以从构造函数中调用addSource
函数。
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
}
}
}
fun <T> LiveData<T>.squashUpdates() = MediatorLiveData<T>().apply {
addSource(this@squashUpdates) {
postValue(it)
}
}
isHovered.value = true
isSelected.value = true