I created a Flow from which I emit data. When I collect this flow twice, there are 2 different sets of data emitted from the same variable instead of emitting the same values to both collectors.
I have a simple Flow that I created myself. The text will be logged twice a second
val demoFlow: Flow<String> = flow {
while (true) {
val text = "Flow ${(0..100).random()}"
Log.d("TAG", text)
emit(text)
delay(1000)
}
}
In my viewModel I have a simple function that gets the previous Flow
fun getSimpleFlow() = FlowRepository.demoFlow
And in my Fragment I collect and display my Flow
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.getSimpleFlow().collect {
binding.tv1.text = it
}
}
launch {
viewModel.getSimpleFlow().collect {
binding.tv2.text = it
}
}
}
}
If I transform the Flow to a StateFlow or a SharedFlow, I no longer have this problem. I don't understand how or why this happens since I'm using the same 'demoFlow' variable. Is there a way to get the same values from 'demoFlow' without converting to a StateFlow or a SharedFlow?
CodePudding user response:
Regular Flow
s are cold, this behaviour is by design.
The demoFlow
is the same, so you have the same Flow
instance. However, collecting the flow multiple times actually runs the body inside the flow { ... }
definition every time from the start. Each independent collection has its own variable i
etc.
Using a StateFlow
or a SharedFlow
allows to share the source of the flow between multiple collectors. If you use shareIn
or stateIn
on some source flow, that source flow is only collected once, and the items collected from this source flow are shared and sent to every collector of the resulting state/shared flow. This is why it behaves differently.
In short, reusing a Flow
instance is not sufficient to share the collection. You need to use flow types that are specifically designed for this.