Reputation: 565
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 theSTOPPED
state, whereas collecting from aStateFlow
or any other flow does not stop collecting automatically. To achieve the same behavior,you need to collect the flow from aLifecycle.repeatOnLifecycle
block.
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()
?
Upvotes: 4
Views: 3580
Reputation: 941
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.
Upvotes: 1
Reputation: 11
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 */ }
Upvotes: 1