Replaced SingleLiveEvent with kotlin Channel / Flow

Tram Ho


When we work with LiveData, sometimes we will have trouble with LiveData observer again when we back from another monitor. This is bad when we want to do one-time tasks like displaying notifications, switching screens, or displaying dialogs, etc.To fix that, we usually implement a clss called SingleLiveEvent. . It really helps in this case, but with the increasing popularity of kotlin and coroutine, we have more options to handle the above work. In this article, I will introduce to you Chanel and Flow of Coroutine to replace SingleLiveEvent.

1. Channel

Channels provide a way to transfer a stream of values. Instead of using val action = SingleLiveEvent<Action>() we will change to val action = Channel<Action>(Channel.BUFFERED) and call it to use: viewModel.action.onEach{ ... }.launchIn(lifecycleScope)

And as we expected, the action was not recalled


However, the channel is tied to the lifecycle of the view, so when the view is destroyed, the channel is also destroyed. And the action is not called when the screen is recreated

2. BroadcastChannel + Flow

To solve the above problem, we can use BroadcastChannel + Flow . Let’s see how to deploy

  • ViewModel

  • View

2.1 Comparing Channel vs BroadcastChannel

Using the first approach to Channel, it implements SendChannel and ReceiveChannel and both will be destroyed when the view is destroyed. On the other hand, BroadcastChannel only implements SendChannel. New GetChannel is created to collect items from BroadcastChanel (openSubscription) every time we launch Thread (from .asFlow). This way, only GetChannel is closed when the view is destroyed and BroadcastChannel is on hold.

2.2 launch vs launchWhenStarted

As we know LiveData is only observer when LifecycleOwner is active (State.STARTED).

If we use the launch on our solution, we might run into a problematic situation:

Application in the background

Our monitor has switched to saveState state but our action continues to be consumed. So it can lead to an exception if we are trying to perform a transaction.

Using launchWhenStarted, we cause the LiveData variable to pause consumption if the lifecycle state is “lower” than Started.

3. References

Share the news now

Source : Viblo