Why not to use LiveData to handle UI event? Because LiveData will trigger again upon configuation change / screen rotation. We want to handle UI event such as click once only.
The above problem could be solved using SingleLiveEvent.
Alternatively, you can use Event wrapper.
open class Event<out T>(private val value: T) { private val pending = AtomicBoolean(true) fun getIfPending(): T? { return if (pending.compareAndSet(true, false)) { value } else { null } } fun peek(): T = value fun isPending(): Boolean = pending.get()}
NOTE: Based on Event by JoseAlcerreca
NOTE: Solution for multiple observers (I didn't try this)
Usage
val selectItemEvent = MutableLiveData<Event<Int>>()
// trigger ui event on item selectedselectItemEvent.value = Event(10)
selectItemEvent.observe(lifecycleOwner, Observer { event -> val position = event.getIfPending() if (position != null) { // do something }})
To reduce boilerplate code, you can use an EventObserver
.
class EventObserver<T>(private val observe: (T) -> Unit) : Observer<Event<T>> { override fun onChanged(event: Event<T>?) { event?.getIfPending()?.let { value -> observe(value) } }}
NOTE: Based on EventObserver by JoseAlcerreca
selectItemEvent.observe(lifecycleOwner, EventObserver { position -> // do something})