如何从 MutableLiveData 发出不同的值?
How to emit distinct values from MutableLiveData?
我观察到 MutableLiveData
会触发观察者 onChanged
,即使向其 setValue
方法提供了相同的对象实例也是如此。
//Fragment#onCreateView - scenario1
val newValue = "newValue"
mutableLiveData.setValue(newValue) //triggers observer
mutableLiveData.setValue(newValue) //triggers observer
//Fragment#onCreateView - scenario2
val newValue = "newValue"
mutableLiveData.postValue(newValue) //triggers observer
mutableLiveData.postValue(newValue) //does not trigger observer
如果向 setValue()
/postValue()
提供相同或等效的实例,是否有办法避免观察者被通知两次
我尝试扩展 MutableLiveData
但没有成功。我可能在这里遗漏了一些东西
class DistinctLiveData<T> : MutableLiveData<T>() {
private var cached: T? = null
@Synchronized override fun setValue(value: T) {
if(value != cached) {
cached = value
super.setValue(value)
}
}
@Synchronized override fun postValue(value: T) {
if(value != cached) {
cached = value
super.postValue(value)
}
}
}
您可以使用以下魔术来消耗“相同的物品”:
fun <T> LiveData<T>.distinctUntilChanged(): LiveData<T> = MediatorLiveData<T>().also { mediator ->
mediator.addSource(this, object : Observer<T> {
private var isInitialized = false
private var previousValue: T? = null
override fun onChanged(newValue: T?) {
val wasInitialized = isInitialized
if (!isInitialized) {
isInitialized = true
}
if(!wasInitialized || newValue != previousValue) {
previousValue = newValue
mediator.postValue(newValue)
}
}
})
}
如果要检查引用相等性,那就是!==
。
但它已被添加到 Transformations.distinctUntilChanged
。
API 中已有:Transformations.distinctUntilChanged()
distinctUntilChanged
public static LiveData<X> distinctUntilChanged (LiveData<X> source)
Creates a new LiveData
object does not emit a value until the source
LiveData value has been changed. The value is considered changed if
equals()
yields false
.
<<snip remainder>>
如果我们谈论 MutableLiveData
,您可以创建一个 class 并覆盖 setValue,然后仅在 new value != old value
时通过 super 调用
class DistinctUntilChangedMutableLiveData<T> : MutableLiveData<T>() {
override fun setValue(value: T?) {
if (value != this.value) {
super.setValue(value)
}
}
}
在我的例子中,我有相当复杂的对象,我必须按某些字段进行比较。为此,我更改了 EpicPandaForce 的回答:
fun <T> LiveData<T>.distinctUntilChanged(compare: T?.(T?) -> Boolean = { this == it }): LiveData<T> = MediatorLiveData<T>().also { mediator ->
mediator.addSource(this) { newValue ->
if(!newValue.compare(value)) {
mediator.postValue(newValue)
}
}
}
默认情况下它使用标准 equals
方法,但如果您需要 - 您可以更改区分逻辑
我观察到 MutableLiveData
会触发观察者 onChanged
,即使向其 setValue
方法提供了相同的对象实例也是如此。
//Fragment#onCreateView - scenario1
val newValue = "newValue"
mutableLiveData.setValue(newValue) //triggers observer
mutableLiveData.setValue(newValue) //triggers observer
//Fragment#onCreateView - scenario2
val newValue = "newValue"
mutableLiveData.postValue(newValue) //triggers observer
mutableLiveData.postValue(newValue) //does not trigger observer
如果向 setValue()
/postValue()
我尝试扩展 MutableLiveData
但没有成功。我可能在这里遗漏了一些东西
class DistinctLiveData<T> : MutableLiveData<T>() {
private var cached: T? = null
@Synchronized override fun setValue(value: T) {
if(value != cached) {
cached = value
super.setValue(value)
}
}
@Synchronized override fun postValue(value: T) {
if(value != cached) {
cached = value
super.postValue(value)
}
}
}
您可以使用以下魔术来消耗“相同的物品”:
fun <T> LiveData<T>.distinctUntilChanged(): LiveData<T> = MediatorLiveData<T>().also { mediator ->
mediator.addSource(this, object : Observer<T> {
private var isInitialized = false
private var previousValue: T? = null
override fun onChanged(newValue: T?) {
val wasInitialized = isInitialized
if (!isInitialized) {
isInitialized = true
}
if(!wasInitialized || newValue != previousValue) {
previousValue = newValue
mediator.postValue(newValue)
}
}
})
}
如果要检查引用相等性,那就是!==
。
但它已被添加到 Transformations.distinctUntilChanged
。
API 中已有:Transformations.distinctUntilChanged()
distinctUntilChanged
public static LiveData<X> distinctUntilChanged (LiveData<X> source)
Creates a new
LiveData
object does not emit a value until the source LiveData value has been changed. The value is considered changed ifequals()
yieldsfalse
.<<snip remainder>>
如果我们谈论 MutableLiveData
,您可以创建一个 class 并覆盖 setValue,然后仅在 new value != old value
class DistinctUntilChangedMutableLiveData<T> : MutableLiveData<T>() {
override fun setValue(value: T?) {
if (value != this.value) {
super.setValue(value)
}
}
}
在我的例子中,我有相当复杂的对象,我必须按某些字段进行比较。为此,我更改了 EpicPandaForce 的回答:
fun <T> LiveData<T>.distinctUntilChanged(compare: T?.(T?) -> Boolean = { this == it }): LiveData<T> = MediatorLiveData<T>().also { mediator ->
mediator.addSource(this) { newValue ->
if(!newValue.compare(value)) {
mediator.postValue(newValue)
}
}
}
默认情况下它使用标准 equals
方法,但如果您需要 - 您可以更改区分逻辑