-
Star
(186)
You must be signed in to star a gist -
Fork
(16)
You must be signed in to fork a gist
-
-
Save JoseAlcerreca/e0bba240d9b3cffa258777f12e5c0ae9 to your computer and use it in GitHub Desktop.
/** | |
* An [Observer] for [Event]s, simplifying the pattern of checking if the [Event]'s content has | |
* already been handled. | |
* | |
* [onEventUnhandledContent] is *only* called if the [Event]'s contents has not been handled. | |
*/ | |
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> { | |
override fun onChanged(event: Event<T>?) { | |
event?.getContentIfNotHandled()?.let { value -> | |
onEventUnhandledContent(value) | |
} | |
} | |
} |
Thanks @JoseAlcerreca.
It's also possible to create an extension to MutableLiveData
to directly post an Event
:
fun <T> MutableLiveData<Event<T>>.postEvent(content: T) {
postValue(Event(content))
}
And to replace usage with:
mutableLiveData.postValue(Event(data)) => mutableLiveData.postEvent(data)
Am I wrong or can't EventObserver handle null events? i.e. new Event<>(null). I'm not in Kotlin but when I got it right
it?.getContentIfNotHandled()?.let(onEventUnhandledContent)
onEventUnhandledContent
is only called if event != null and the return value != null so with new Event<>(null)
onEventUnhandledContent
is never called?!
I've tweaked some code a bit to allow nulling the content. I'm new to kotlin so please correct me if there are any issues
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set // Allow external read but not write
fun handleContent() : T {
hasBeenHandled = true
return content
}
/**
* Returns the content, even if it's already been handled.
*/
fun peekContent(): T = content
}
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
override fun onChanged(event: Event<T>?) {
event?.let {
if (it.hasBeenHandled) return
onEventUnhandledContent(it.handleContent())
}
}
}
I use https://github.com/Zhuinden/live-event now
I hear that a
LinkedListChannel
exposed as a Flow would have the same effect, but without the magic.
As you are probably aware it also needs a custom collector to work reliably.
I use https://github.com/Zhuinden/live-event now
This is fine solution too, supporting multiple observers and multiple queued events, but with a small catch: only one observer receives these queued events.
@gmk57 this is true. Theoretically it'd be possible to either expose setPaused
from command-queue and/or provide a "minimumSubscriberCount" (working name) that would make it so that under 3 subscribers the EventEmitter is paused
inline fun <T> LiveData<Event<T>>.observeEvent(owner: LifecycleOwner, crossinline onEventUnhandledContent: (T) -> Unit) { observe(owner, Observer { it?.getContentIfNotHandled()?.let(onEventUnhandledContent) }) }
I finished it like this. It seems to work correctly. What's your opinion?
inline fun LiveData<Event>.observeEvent(owner: LifecycleOwner, crossinline onEventUnhandledContent: (T) -> Unit) {
observe(owner) { it?.getContentIfNotHandled()?.let(onEventUnhandledContent) }
}
Can't you just emit the event using
offer()
though? That way you don't need to create aCoroutineScope
.The
SendChannel<T>.offer()
documentation says this:and the
LinkedListChannel
, say this:I've been using the event-emitter library from Zhuinden, but since I'm already using coroutines. I've been trying to implement the same behavior using only coroutines.