Kotlin / kotlinx.coroutines

Library support for Kotlin coroutines
Apache License 2.0
12.94k stars 1.84k forks source link

ArrayBroadcastChannel that delivers new subscribers a value #1761

Closed codeversed closed 4 years ago

codeversed commented 4 years ago

In our current codebase, we are using ArrayBroadcastChannels to perform detailed logging. This works great since it does not conflate anything, which is what we need for our logs to be complete.

Our problem is that we want to use the same BroadcastChannels to update our UI. If the UI subscriber is created after the BroadcastChannel is first initialized, the UI will never show values unless another broadcast would take place. This is where the ConflatedBroadcastChannels would solve our UI problem when it delivers new subscribers with the latest (or even last) value.

Currently, I do not see any possible path forward except having duplicate BroadcastChannels (one being an ArrayBroadcastChannel for logging, and one being ConflatedBroadcastChannel for the UI). I was considering extending one of those classes our creating my own class to handle this situation but it seems this would be a difficult path forward with classes that I would need being marked private.

Please let me know if anyone has found a solution to a similar situation. Maybe I am missing something and this can easily be accomplished. Thanks in advance for reading this!

zach-klippenstein commented 4 years ago

I think your use case could be solved with Flow if it had an operator like RxJava's replay(1) (#1261).

codeversed commented 4 years ago

We currently receive the BroadcastChannel as a Flow using asFlow(). Since ArrayBroadcastChannel holds on to the values broadcasted, this could be a good path forward to add a replay to flow.

I guess I would want to understand why ArrayBroadcastChannel does not send a value to new subscribers in the first place. It seems like this is on purpose that they wanted to not mimic RxJava's implementation.

RBusarow commented 4 years ago

LiveData has this replay(1) behavior, right? And it wasn't long after it was announced that people started talking about SingleLiveEvent, which basically just removes that replay behavior (basically...).

https://github.com/android/architecture-components-samples/issues/63

Both behaviors have their place. Event streams such as click events should probably be stateless without a replay. State streams like a view state should probably be stateful with a replay.

codeversed commented 4 years ago

Both behaviors have their place. Event streams such as click events should probably be stateless without a replay. State streams like a view state should probably be stateful with a replay.

@RBusarow good points. I guess our setup is more of a unique case that I would love to reduce the number of event streams.

I would need to set up some more tests to confirm but our main concern for our logging portion is that we do not want to drop any data due to the number of events being sent to each channel (aka backpressure). This is why we are using the ArrayBroadcastChannel vs ConflatedBroadcastChannel.

I was looking into the Flow.share from the linked thread. This new share could solve our issue but need to see the final implementation of it and test how it works.

elizarov commented 4 years ago

Here is a design for SharedFlow that covers this use-case of combining buffered broadcast channel with the replay of the last value. See #2034

elizarov commented 4 years ago

Closing this issue as superseded by the design of shared flows in #2034.