StateFlow and SharedFlow: the new hot stream APIs in town
There's been quite a hype around the (kind of) newly introduced StateFlow
and SharedFlow
in Kotlin/Android community.
These are the new Kotlin Flow
APIs. But these are not for "cold" streams (i.e. data are generated and emitted when there's a subscriber). These are for "hot" streams (i.e. data are emitted anyway and any active subscribers will receive them).
If this reminds you of LiveData
it's because this is another "hot" stream implementation. The data are emitted anyway from the ViewModel, and any subscriber in the View will get those values.
So should we replace LiveData
with StateFlow
? Is it that simple? And does it worth it?
StateFlow
The API for StateFlow
is almost identical to LiveData
. You have a MutableStateFlow
that "drives" the StateFlow
(similar to how a MutableLiveData
"drives" a LiveData
).
- In contrast with
LiveData
,StateFlow
always needs an initial value. - This runs when the lifecycle is at least in the
STARTED
state.
Note that (2) might be an issue. LiveData
automatically unregisters the consumer when the view goes to the STOPPED state. When collecting a StateFlow
this is not handled automatically.
To address this issue you can either start and stop collecting values from StateFlow
manually, or just convert your Flow to a LiveData
for getting the best of both worlds (this extension method is included in the lifecycle-livedata-ktx
library).
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
viewModel.userName.asLiveData().observe(viewLifecycleOwner) {
userName -> userNameLabel.text = userName
}
}
}
SharedFlow
You can think of SharedFlow
as a generalization of StateFlow
.
StateFlow
by default emits the last known value when there's a new subscriber. WithSharedFlow
, you can configure how many previous values to be emitted.- You can define what happens when the buffer of values is full (e.g. drop values, suspend caller, etc).
- It provides a
subscriptionCount
that indicates how many active collectors exist to define business logic accordingly. - It provides a
resetReplayCache()
for not emitting the last known values if there are new subscribers.
This offers great flexibility for more advanced use cases that LiveData
cannot fulfil easily.
Is it worth it?
The idea is that we can get rid of Jetpack's LiveData
and use the platform-independent StateFlow
/SharedFlow
in all the layers of an app (view, model, storage). LiveData
being so Android Lifecycle-depended is no good fit for using it outside of Views/ViewModels.
StateFlow
API is almost identical to LiveData
and the SharedFlow
offers flexibility for more advanced use cases. Since you can get all the advantages of LiveData
(which is the automatic subscribing/unsubscribing when the app goes to the background) I think that these new APIs are the way to go if you are building a new app.