Skip to content

Instantly share code, notes, and snippets.

@rharter
Last active April 8, 2020 20:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rharter/f54af6c0f84e4b6c7716232cd88d76f9 to your computer and use it in GitHub Desktop.
Save rharter/f54af6c0f84e4b6c7716232cd88d76f9 to your computer and use it in GitHub Desktop.
LiveData that only delivers new events to observers.
import android.arch.lifecycle.LifecycleOwner
import android.arch.lifecycle.LiveData
import android.arch.lifecycle.MediatorLiveData
import android.arch.lifecycle.Observer
fun <T> LiveData<T>.toLiveEvent(): LiveEvent<T> {
return when (this) {
is LiveEvent -> this
else -> LiveEvent<T>().apply {
addSource(this, { value = it })
}
}
}
open class LiveEvent<T>() : MediatorLiveData<T>() {
constructor(initialValue: T): this() {
value = initialValue
}
private val observers = mutableMapOf<Observer<T>, StartVersionObserver>()
private val wrappedObservers = mutableMapOf<StartVersionObserver, Observer<T>>()
private var version = 0
override fun observe(owner: LifecycleOwner, observer: Observer<T>) {
val wrapped = observers[observer] ?: StartVersionObserver(version, observer).also {
observers[observer] = it
wrappedObservers[it] = observer
}
super.observe(owner, wrapped)
}
override fun observeForever(observer: Observer<T>) {
val wrapped = observers[observer] ?: StartVersionObserver(version, observer).also {
observers[observer] = it
wrappedObservers[it] = observer
}
super.observeForever(wrapped)
}
override fun removeObserver(observer: Observer<T>) {
// since we dont' know where this will be called from, `observer` could be
// the original observable or the wrapped observable, so we need to make sure
// we update our current observer state and pass the wrapped observer to the
// super.
val originalObserver = wrappedObservers.remove(observer) ?: observer
val wrapped = observers.remove(originalObserver) ?: return
if (observer == originalObserver) wrappedObservers.remove(wrapped)
super.removeObserver(wrapped)
}
override fun setValue(value: T?) {
version++
super.setValue(value)
}
// Used when T is Unit, to make calls easier
fun call() {
value = null
}
internal inner class StartVersionObserver(
startVersion: Int,
val observer: Observer<T>) : Observer<T> {
private var lastSeenVersion = startVersion
override fun onChanged(t: T?) {
if (lastSeenVersion < this@LiveEvent.version) {
lastSeenVersion = this@LiveEvent.version
observer.onChanged(t)
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment