13

我观察到即使向其方法提供了相同的对象实例,也会MutableLiveData触发观察者。onChangedsetValue

//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)
        }
    }
}
4

4 回答 4

35

API中已经有:Transformations.distinctUntilChanged()

distinctUntilChanged

public static LiveData<X> distinctUntilChanged (LiveData<X> source)

创建一个新LiveData对象,在源 LiveData 值更改之前不会发出值。equals()如果yield ,则认为该值已更改 false

<<剪断余数>>

于 2019-03-24T21:08:19.243 回答
12

您可以使用以下魔术来消耗“相同的项目”:

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.

于 2019-02-11T21:41:24.903 回答
3

如果我们谈论MutableLiveData,您可以创建一个类并覆盖 setValue 然后仅通过 super if 调用new value != old value

class DistinctUntilChangedMutableLiveData<T> : MutableLiveData<T>() {
    override fun setValue(value: T?) {
        if (value != this.value) {
            super.setValue(value)
        }
    }
}
于 2019-06-12T14:25:05.297 回答
1

就我而言,我有相当复杂的对象,我必须通过某些字段进行比较。为此,我改变了 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方法,但如果您需要 - 您可以更改区分逻辑

于 2019-10-04T08:44:43.360 回答