Matti MK
02/02/2022, 8:46 PMStateFlow
from Compose, the issue is that the state always “restarts” from initial state when switching between screens on bottom nav. This is an issue when the VM has something different than the initial state, as for some reason the Compose local state always restarts from intial state, before getting the updated state from the VM.
On the VM side my flow looks as follows:
public val viewState: StateFlow<ScreenState> = _internalState.stateIn(
clientScope,
SharingStarted.WhileSubscribed(),
ScreenState(showLoading = true)
)
And on my Compose screen collection looks like so:
fun Screen(
viewModel: ViewModel = getViewModel(),
) {
val lifecycleOwner = LocalLifecycleOwner.current
val viewStateFlow = remember(viewModel.viewState, lifecycleOwner) {
viewModel.viewState.flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED)
}
val viewState by viewStateFlow.collectAsState(ViewModel.ScreenState(showLoading = true))
Logger.i { "VM state ${viewModel.viewState.value}" } // 1
Logger.i { " Screen local state is ${viewState}" } // 2
showLoading = false
. Once the screen is entered the first time the initial state is correct, but if I navigate to another screen and then back to this screen the VM state will no longer be showLoading = true
, however, the viewState
local to Compose Screen always restarts from the showLoading = true
before getting the updated value from the VM.
So, in the above sample prints of // 1
and // 2
will print out different values when entering the screen after viewModel.viewState.value}
!= initial value.StateFlowValueCalledInComposition
and set the initial value as what ever is on the VM’s state everything works just fine:
val viewState by viewStateFlow.collectAsState(viewModel.viewState.value)
I guess this is not the way to go 😅Albert Chang
02/03/2022, 2:36 AMStateFlow
. viewStateFlow
is a Flow
so you must specify an initial value yourself. val viewState by viewStateFlow.collectAsState(viewModel.viewState.value)
actually makes sense if you really want to use flowWithLifecycle
.Matti MK
02/03/2022, 2:44 AMAlbert Chang
02/03/2022, 7:28 AMStylianos Gakis
02/03/2022, 12:24 PMval viewState by viewModel.viewState.collectAsState()
? Your VM viewState has a loading = true as a default anyway inside the stateIn
and it by itself can launch the coroutine and change the _internalState which will automatically change the viewState
. I must be misunderstanding something here.Matti MK
02/03/2022, 1:03 PMStateFlow
to Flow
in order to have lifecycle-based consuming of the flow. With that in mind, I don’t think the val viewState by viewModel.viewState.collectAsState()
respects the consumer’s lifecycle, however, using SharingStarted.WhileSubscribed
might have the same effect?Stylianos Gakis
02/03/2022, 1:08 PMproduceState
which says that it is launched when entering composition and stops when exiting composition, this is what you want to achieve is it not?Matti MK
02/03/2022, 1:26 PMStylianos Gakis
02/03/2022, 1:30 PMWhileSubscribed
Matti MK
02/03/2022, 1:42 PM