I started to replace LiveData with Flow since it is more flexible. But then I find out you need to write enormous amount of boilerplate code to observe from Flow in UI.
In the StateFlow documentation, it says that
LiveData.observe()automatically unregisters the consumer when the view goes to theSTOPPEDstate, whereas collecting from aStateFlowor any other flow does not stop collecting automatically. To achieve the same behavior,you need to collect the flow from aLifecycle.repeatOnLifecycleblock.
It's also mentioned in the article by Manuel Vivo that using collecting from lifecycleScope.launchWhenX is dangerous and should not be used in UI because the producer flow will not stop emitting.
He recommended us to use
// Listen to multiple flows
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
// As collect is a suspend function, if you want to collect
// multiple flows in parallel, you need to do so in
// different coroutines
launch {
flow1.collect { /* Do something */ }
}
launch {
flow2.collect { /* Do something */ }
}
}
}
The amount of boilerplate code is too much. Is it not possible to do it in a two liner like what LiveData does?
viewModel.movieData.observe(viewLifecycleOwner) {
...
}
Why is it so complex to collect from Flow in UI? Is it advisable to convert the Flow to LiveData with asLiveData()?
You could build extensions to reduce the boilerplate
inline fun <T> Flow<T>.collectIn(
owner: LifecycleOwner,
minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
coroutineContext: CoroutineContext = EmptyCoroutineContext,
crossinline action: suspend CoroutineScope.(T) -> Unit
) = owner.addRepeatingJob(minActiveState, coroutineContext) {
collect {
action(it)
}
}
This makes collecting flows similar to LiveData as
flow.collectIn(viewLifecycleOwner){ /* do stuff */ }
First answer your first question: Flow is a cold flow. And Flow is stateless. If you provide Flow, then it means that you need to construct and collect Flow frequently.
In another case, if Hot Flow is provided, such as (StateFlow), although the hot flow provides state (.value), it does not know anything about the life cycle of Android. As you said, you can use launchWhenXXX() to collect Flow.
When using launchWhenXXX(), you must pay attention to the life cycle of the hot flow. When to start collect and when to end collect, these need to be paid attention to. So it seems very troublesome. Of course, Flow is a way to get rid of using LiveData.
For details, please refer to: https://proandroiddev.com/should-we-choose-kotlins-stateflow-or-sharedflow-to-substitute-for-android-s-livedata-2d69f2bd6fa5
The second question: LiveData manages the life cycle of Android. Flow.asLiveData() is completely desirable. At this time, only a simple Observe is needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With