Is there any way to make a `callbackFlow` shareabl...
# coroutines
b
Is there any way to make a
callbackFlow
shareable, without requiring a
CoroutineScope
(as required inside the
shareIn()
extension)?
Basically, I don't want to register the callback I'm changing into a flow multiple times.
j
How would expect it to work conceptually? The
shareIn
operator needs a scope because it needs to start a coroutine that will collect your cold flow and broadcast the values to subscribers. This coroutine needs a scope to run
☝️ 1
b
Something similar to
MutableSharedFlow
(which doesn't need a scope to be created), but that can keep track of subscribers and unregisters the callback.
I'm actually looking at
produce()
, but that might not handle shutting down the callback if no collectors are subscribed to the flow I can create from it.
z
Instead of using callbackFlow, use MSF with onSubscription to register a callback?
b
Wouldn't onSubscription be called each time the flow is subscribed to?
Well, I guess I can get the subscription count, and just unregister if it's 0.
No, that makes no sense. Won't be called if it's 0
But I can use
onCompletion
to track it instead. This might be the best approach.
Interesting... So I took a dive into the
shareIn()
code to figure out why it really needs a
CoroutineScope
and it makes sense when converting a cold flow to a hot flow, as they collect the
subscriptionCount
state flow and map the upstream flow to the downstream flow based on the differing subscription events, or
SharingStarted
passed. However, it doesn't make sense if you want to broadcast the results of a callback to multiple collectors by doing
callbackFlow {}.shareIn()
. The "upstream flow" is actually a
producer
, which accepts the events from the callback itself. So really, the upstream flow is the callback emitting the events. Say we are using
trySendBlocking()
to emit the events on the callbackFlow, then we can just do something like:
Copy code
if (!sharedFlow.tryEmit(value)) { runBlocking { sharedFlow.emit(value) } }
on the callback event emit instead. Once we have that, we can just do a
transformLatest
off the
subscriptionCount
and the
SharingStarted
value passed, pass that as a wrapped shared flow, and then we can have a "shared" callbackFlow.
If this makes no sense, I'll try to make this whole thing more coherent tomorrow when I'm more clear headed (🍻). The TL;DR is that I think I can make a
SharedFlow
from a callback without the need for
callbackFlow {}.shareIn()
or the use of any coroutine scopes (other than when you collect on it).
Spent much of last night trying to decipher what my ramblings were about the night before. Only thing I can figure is I was trying to make my own coroutine via
ChannelCoroutine
that was somehow tied the number of subscribers of the flow. I'll admit whatever madness I was chasing is lost in the past now.