Reactive Streams on Kotlin: SharedFlow and StateFlow

In this tutorial, you’ll learn about reactive streams in Kotlin and build an app using two types of streams: SharedFlow and StateFlow. By Ricardo Costeira.

5 (20) · 3 Reviews

Download materials
Save for later
Share
You are currently viewing page 4 of 4 of this article. Click here to view the first page.

Subscribing to State Updates

Open CoinListFragment.kt. Find observeViewStateUpdates() and update it to:

private fun observeViewStateUpdates(adapter: CoinAdapter) {
  viewLifecycleOwner.lifecycleScope.launchWhenStarted {
    viewModel.viewState.collect { updateUi(it, adapter) }
  }
}

This code is much like what you did with SharedFlow in the sense that the same logic applies. Despite this, you might worry about the state flow emitting values when the app is in the background. But you don’t need to. It’s true that, because it’s scoped to viewModelScope, it’ll still emit even without any subscribers as long as the ViewModel exists. Regardless, state flow emissions are lightweight operations: It’s just updating the value and notifying all subscribers. Plus, you probably do want the app to show you the latest UI state when it comes to the foreground.

Build and run the app. Everything should work as before because you just refactored the code. Good job on using StateFlow!

Crypto Stonks 5000 - Shared events between screens

StateFlow and Channels

Like SharedFlow can replace BroadcastChannel completely, StateFlow can replace ConflatedBroadcastChannel completely. There are a couple reasons for this. StateFlow is simpler and more efficient than ConflatedBroadcastChannel. It also has better distinction between mutability and immutability with MutableStateFlow and StateFlow.

Hot Flows, RxJava and LiveData

You’re now aware of how both SharedFlow and StateFlow work. But are they even useful on Android?

Although they might not bring anything “new”, they provide more direct and efficient alternatives to the table. For instance, wherever you’d use an RxJava‘s PublishSubject, you can use a SharedFlow. Or wherever you’d use a BehaviorSubject, you can probably use a StateFlow. In fact, if hot event emission is not an issue, StateFlow can even easily replace LiveData.

Note: You can also convert SharedFlow and StateFlow objects in to LiveData as well with the AndroidX lifecycle-livedata-ktx library. The library provides an extension method asLiveData() that allows you to convert the flow and expose it as LiveData for consumption in your view. For more details, see the StateFlow, Flow, and LiveData section of the Android Developers StateFlow and SharedFlow article.

So, putting it in simpler terms:

  • If you have some kind of state management, you can use StateFlow.
  • Whenever you have some event stream going on, where it’s not a problem if events aren’t handled by all possible subscribers or past events might not be handled at all, you can use SharedFlow.

Challenge: Using SharedFlow To Handle Screen Events

Congratulations! This concludes the tutorial. If you want to go the extra mile, you can also handle the screen-specific events modeled in the CoinListFragmentViewEffects and CoinHistoryFragmentViewEffects classes using shared flows. These are events that should be handled exactly once, which means a simple Channel would fit better — remember that shared flows drop events when there are no subscribers. Still, you can do it with shared flows for practice. If you’re curious, the final project in the project materials has a sample implementation.

Where to Go From Here?

If you want to learn more about StateFlow and SharedFlow, you can check their corresponding documentation pages here and here, respectively.

You can also find some information specific to shared and state flows usage on Android in the Android developers page.

If you’re curious about turning cold flows into hot ones, you can check out the following articles:

Finally, if the challenge section piqued your interest in using Channels to handle screen events, you can check out this interesting article on Medium.

I hope you enjoyed this tutorial. If you have any questions, tips or comments, feel free to join the discussion below. :]