-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Convert ReceiveChannel<T>
to Flow<T>
without consuming
#1490
Comments
Why would you need to have it exposed as |
@elizarov because a // this is fine
launch {
for (event in viewModel.events()) {
ui.handleEvent(event)
}
} // this is a bug, because on rotation when you subscribe again to the same channel instance
// we get a crash because the channel is already closed
launch {
viewModel.events()
.consumeEach { event -> ui.handleEvent(event) }
} |
Thanks. That's clear. How about |
perfect name! My original thinking is that |
Hey @ZakTaccardi , @elizarov. I have had a look at this issue , no one has implemented it yet and would love to take it up and raise a pr on this. To implement this i was thinking of such an approach .
Any thoughts and feedback on this will be appreciated on whether the approach is feasible or not. Thanks. |
There should not be any cut-and-paste in this method implementation, as we are concerned about the overall size of the library. I've sketched the right-looking implementation in this commit: b16beb0 It needs tests, though. There are also open design issue with respect to the consistency of operator naming and its interaction with |
Thanks for the feedback. I have seen the implementation and definitely learned from it. |
Here's a super basic implementation, though may have race conditions where the /**
* Converts `this` [ReceiveChannel] into a [Flow] without closing the [ReceiveChannel] when the [Flow] is cancelled.
*/
fun <T> ReceiveChannel<T>.receiveAsFlow(): Flow<T> = flow {
val flowCollector = this
for (item in this@receiveAsFlow) {
flowCollector.emit(item)
}
} |
* Experimental ReceiveChannel.receiveAsFlow extension convert channel to flow in fan-out fashion allowing for multi-use. * Also, ReceiveChannel.consumeAsFlow is promoted to experimental from preview Fixes #1490
@ZakTaccardi I have faced a weird problem as your implementation worked for me, that I was using kotlinx coroutines with vertx kotlin coroutine extension where they expose the pubsub as a channel, and I tried to use it as a receive flow by the extensions to channel. Unfortunately it didn't work, and so I came up with the equivalent of what you did: @ExperimentalCoroutinesApi
fun <T> ReceiveChannel<T>.receiveAsFlowByIterationUnsafe(): Flow<T> = flow {
this@receiveAsFlowByIterationUnsafe.consumeEach { emit(it) }
} The original form is like this: val eventFlow = flow { vertx.eventBus().localConsumer<Event<String, NetSocket>>("fire").toChannel(vertx).consumeEach { emit(it) } }
// do any thing... After I checked out the consumeEach function I see that it is shockingly the same as you do, and also because receiveAsFlow and Flow.emitAll(chan: ReceiveChannel) are equivalent we cannot use it as an alternative substitute. So I'm also left hanging with the problem you faced It seems like we need to do a redesign regarding channel and flow. I don't know why, but for some reason there aren't receiveOrClosed from RendezvousChannel? Anyway, this might be the final form of my extension that preserved the relations receiveAsFlow had while sidestepping the receiveOrClosed abstract method problem: @ExperimentalCoroutinesApi
fun <T> ReceiveChannel<T>.receiveAsFlowByIteration(): Flow<T> = flow {
cancel(CancellationException("receive stream terminated",
this@receiveAsFlowByIteration.runCatching { while (!isClosedForReceive) emit(receive()) }
.exceptionOrNull()
))
} |
My
ViewModel
exposes a stream of events as aReceiveChannel<T>
My activity/fragment observes this stream of events, without consuming on cancellation.
By not consuming on cancellation (unsubscription), this allows my UI to re-use the same
ReceiveChannel<T>
instance across configuration changes.I think the latter function would be useful. Can it be added?
The text was updated successfully, but these errors were encountered: