Hi all! I'm trying to replace a callback API (so a...
# coroutines
j
Hi all! I'm trying to replace a callback API (so an interface with a
addListener(listener)
and
removeListener(listener)
methods) and replace it with a Flow based API. Unfortunately, the only way that I found to do it is by using the deprecated
BroadcastChannel.openSubscription()
. The reason for this is that I want the hot flow returned by my interface to emits all events that happen right after it is returned, not right after we start to collect it. Here is an example, that highlight the issue : https://pl.kotl.in/LE8oUe6xg. I want the first collected click target to be
foo
, but if I use
BroadcastChannel.asFlow()
that's not what I get. Any idea how to do that in a proper way ?
z
I believe it's documented on BroadcastChannel that any items it receives before the first subscriber will be dropped. I believe the replacement for BroadcastChannel, SharedFlow, also behaves this way. Once
shareIn
is released, I think you could do something like this:
Copy code
private val listeningJob = Job()
private val eventChannel = Channel<ClickEvent>(UNLIMITED)

val events: Flow<ClickEvent> =
  eventChannel.receiveAsFlow()
  .shareIn(CoroutineScope(listeningJob), replay = 0, sharingStart = WhileSubscribed())

fun startListening() {
  val listener = {
    eventChannel.offer(it)
  }
  registerListener(listener)
  listeningJob.invokeOnCompletion {
    unregisterListener(listener)
  }
}

fun stopListening () {
  listeningJob.cancel()
}
Unfortunately, the
shareIn
operator hasn't been released yet.
j
@elizarov what would be the non deprecated way of doing that ? Use a raw channel ?
r
Why not just use channel or callback Flow?
ChannelFlow or CallbackFlow
e
If it’s hot, then you should use a plain
Channel
. You can convert it to the
Flow
with
.receiveAsFlow()
extension.