how do I listen to a mutableStateFlow object from ...
# compose
o
how do I listen to a mutableStateFlow object from an Activity? I only want the activity to act on it if it has changed into something other than the default value
a
Seems like more of an #android question
What have you tried so far?
❤️ 1
o
compose is android
Copy code
lifecycleScope.launchWhenCreated {
            viewModel.uiState.collect {
                if (it.authenticated) {
                    setContent {
                        Home()
                    }
                } else {
                    setContent {
                        Authentication()
                    }
                }
            }
        }
authenticated will be set to true whenever some method inside the viewmodel is done and changes it in the state object
a
MutableStateFlow and Activities aren't compose 🙂
o
but Compose is the one that encourages this pattern of state change
I would just use a LiveData and observe it if it werent for my using compose
yea i dunno honestly
you’re probably right
thanks anyway
a
If you're using flows this looks like a case for
distinctUntilChanged
The philosophy of state that compose uses isn't particularly unique to compose; it's highly useful with things like flows
Same story with LiveData too
o
I see..yea it’s literally the same with LiveData exccept observe does what i want, seems the same concept is in distinctUntilChanged then
so this is coroutines stuff
which compose happens to use
Note that any instance of StateFlow already behaves as if
distinctUntilChanged
operator is applied to it, so applying
distinctUntilChanged
to a
StateFlow
has no effect. See StateFlow documentation on Operator Fusion. Also, repeated application of
distinctUntilChanged
operator on any flow has no effect.
a
Yep. But since you're only using one sub-element of the emitted object, something else about it could be different and cause it to emit from a StateFlow
o
1) I'd suggest using repeatOnLifecycle when collecting flows in activities/fragments. There's several medium articles out there that also exemplify some nice wrappers around it to use to collect flows safely in views. 2) you can break out this property out of the global view state model and have it be its own flow so you only react to changes to that single property, rather then a global view state 3) if you just prefer to still emit a global view state from your VM, then you can update the collector (your activity) to something like
Copy code
viewModel.uiState.map { it.authenicated }.distinctUntilChanged().collect { .... }
And if you wanted to specify some default value here and still use a State flow, then just tack on
stateIn()
before
collect()
It seems like the logic in your VM runs once then emits result so your UI shows the appropriate UI/composable given the authentication result. If this is something you want to only execute once, then it's still part of your app/view state, you may just want to call into the VM to mark that you consumed and handled this state change. Otherwise, it seems like how you have it written should already be fine, even if the view state was emitted several times due to other property changes but with the same authenticated value. Because compose is already smart enough to know if a property it's consuming changed or not and if needs to recalculate/redraw etc.
152 Views