I observed that MutableLiveData
triggers onChanged
of an observer even if the same object instance is provided to its setValue
method.
//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
Is there a way to avoid an observer be notified twice if the same or an equivalent instance is provided to setValue()
/postValue()
I tried extending MutableLiveData
but that did not work. I could be missing something here
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)
}
}
}
There is already in 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>>
You can use the following magic trick to consume "items being the same":
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)
}
}
})
}
If you want to check referential equality, it's !==
.
But it has since been added to Transformations.distinctUntilChanged
.
If we talk about MutableLiveData
, you can create a class and override setValue and then only call through super if new value != old value
class DistinctUntilChangedMutableLiveData<T> : MutableLiveData<T>() {
override fun setValue(value: T?) {
if (value != this.value) {
super.setValue(value)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With