Is it possible to prevent LiveData receive the last value when start observing?
I am considering to use LiveData as events.
For example eve
I created a LiveData object FreshLiveData, which emits the onChange to the observer only after there is a call to setValue or postValue.
FreshLiveData.kt
/**
* A lifecycle-aware observable that emits only new data after subscription. Any data that has
* already been set, before the observable has subscribed, will be ignored.
*
* This avoids a common problem with events: on configuration change (like rotation, font change) an
* update can be emitted if the observer is active. This LiveData only calls the observable if
* there's an explicit call to setValue() or postValue().
*
* All observers will be notified of change(s).
*/
class FreshLiveData : MutableLiveData() {
private val observers = mutableMapOf()
override fun observe(owner: LifecycleOwner, observer: Observer) {
@Suppress("UNCHECKED_CAST")
observer as Observer
observers[owner].apply {
if (this == null) {
observers[owner] = FreshLiveDataObserver(observer).apply {
super.observe(owner, this)
}
} else {
add(observer)
}
}
}
override fun observeForever(observer: Observer) {
@Suppress("UNCHECKED_CAST")
observer as Observer
observers[ProcessLifecycleOwner.get()].apply {
if (this == null) {
observers[ProcessLifecycleOwner.get()] = FreshLiveDataObserver(observer).apply {
super.observeForever(this)
}
} else {
add(observer)
}
}
}
override fun removeObservers(owner: LifecycleOwner) {
observers.remove(owner)
super.removeObservers(owner)
}
override fun removeObserver(observer: Observer) {
@Suppress("UNCHECKED_CAST")
observers.forEach { it.value.remove(observer as Observer) }
super.removeObserver(observer)
}
@MainThread
override fun setValue(t: T?) {
observers.forEach { it.value.setPending() }
super.setValue(t)
}
override fun postValue(value: T) {
observers.forEach { it.value.setPending() }
super.postValue(value)
}
inner class FreshLiveDataObserver(observer: Observer) : Observer {
private val observers = mutableSetOf>()
private val pending = AtomicBoolean(false)
init {
observers.add(observer)
}
fun add(observer: Observer) = observers.add(observer)
fun remove(observer: Observer) = observers.remove(observer)
fun setPending() = pending.set(true)
override fun onChanged(t: T) {
if (pending.compareAndSet(true, false)) {
observers.forEach { observer ->
observer.onChanged(t)
}
}
}
}
}
and here is an extension for transforming an existing LiveData to a FreshLiveData.
LiveDataExtensions.kt
@MainThread
fun LiveData.toFreshLiveData(): LiveData {
val freshLiveData = FreshLiveData()
val output = MediatorLiveData()
// push any onChange from the LiveData to the FreshLiveData
output.addSource(this) { liveDataValue -> freshLiveData.value = liveDataValue }
// then push any onChange from the FreshLiveData out
output.addSource(freshLiveData) { freshLiveDataValue -> output.value = freshLiveDataValue }
return output
}
Usage:
val liveData = MutableLiveData()
liveData.value = false
liveData.toFreshLiveData().observeForever {
// won't get called with `it = false` because the observe was setup after setting that livedata value
// will get called with `it = true` because the observer was setup before setting that livedata value
}
liveData.value = false
val freshLiveData = FreshLiveData()
freshLiveData.value = false
freshLiveData.observeForever {
// won't get called with `it = false` because the observe was setup after setting that livedata value
// will get called with `it = true` because the observer was setup before setting that livedata value
}
freshLiveData.value = true