https://kotlinlang.org logo
Title
v

Vincent Williams

08/13/2020, 8:11 PM
what would you use for effects (like error message, navigation etc) instead of StateFlow? Would just a broadcast channel be used or is that going to be deprecated?
s

streetsofboston

08/13/2020, 8:18 PM
We wrote our own
EventFlow
for that. It is like a StateFlow with respect that it is a hot stream of data, but it differs that it is state-less (a new collector will not receive the last value it had emitted). Think of a StateFlow like it could've been backed by a Conflated Broadcast Channel and of an EventFlow like it could've been backed by a rendezvous Channel.
v

Vincent Williams

08/13/2020, 8:19 PM
ya thats basically exactly what im looking for. Is there a downside to using rendezvous channel directly?
other than the fact that you cant emit a value outside of a suspend function
s

streetsofboston

08/13/2020, 8:37 PM
You can emit a value outside of a coroutine scope context (suspend function) by calling
offer
instead of
send
. But you risk loosing an emission if no one is listening/collecting (but then it wouldn’t be a problem… 🙂 )
v

Vincent Williams

08/13/2020, 8:38 PM
Oh ok. Then I'll probably just use a channel I guess
s

streetsofboston

08/13/2020, 8:40 PM
I have to back-track the “when non one is listening” a bit. Also, if a collector/listener is on a different thread and is too slow in handling an emitted event, it may get lost when using
offer
instead of
send
.
v

Vincent Williams

08/13/2020, 9:15 PM
ah ok. it probably still works for something like an error message or navigation event though
what would cause a listener to be "too slow" to consume an event?
s

streetsofboston

08/13/2020, 9:19 PM
E.g you (your producer) calls
channel.send(event)
in one background thread more than once in really quick succession. And your collector in the UI, on the Main thread (Main dispatcher), which should finish in 16ms, but is somehow a bit slower than the producer calling the
send
method for the 2nd time. Usually this is not a big issue, since Events are often used for navigation and two navigation events should not be emitted in such quick succession (faster than the UI can handle them).
But if you want to be absolutely sure, call the
send
method in the
viewModelScope
for example (assuming here you do Android development). This way you won’t miss sent events (unless the
viewModelScope
itself gets cancelled).
g

gildor

08/13/2020, 11:48 PM
You also could use consumable event approach with StateFlow, so emit special event object with event inside, which can be retrieved only once (consumed) We use this approach in RxJava too
Also you could emulate skipping first event by using .drop(1) operator before returning your Flow instance
v

Vincent Williams

08/13/2020, 11:51 PM
Hmm Rx java has that built in with the publish subject
g

gildor

08/13/2020, 11:52 PM
Yes, but we use this approach not because we missed publish subject, just because it's safer, someone have to dispatch event, so it's harder to lost it
For cases when UI is detached from ViewModel for example, and attached again
So with PublishSubject you will just lost all events which emitted when no one is subscribed
s

streetsofboston

08/14/2020, 3:20 AM
But if you'd use a rendezvous Channel that is backing a (custom) EventFlow, emitting a value by calling
send
on that channel would not risk losing any events, even if the consumer's CoroutineScope is cancelled (eg UI detached), because if the consumer (collector) is detached no one is listening and the sender/producer will just suspend until a new collector arrives (UI re-attached).
g

gildor

08/14/2020, 3:37 AM
Yes, but doesn’t allow have multiple subscribers
It still working solution of course, and will work for most of cases But it wouldn't work like that with PublishSubject
I don’t say it wrong, I just say that there are 2 ways to achieve this, have a single subscriber stream of events with a buffer, or represent it as a consumable state
👍 1