https://kotlinlang.org logo
#compose
Title
# compose
k

Kshitij Patil

12/04/2020, 3:24 PM
What exactly happens when we do
collectAsState()
in it? Do I get a snapshot of snapshot of state and won't receive any further updates or will do? I've a navigation graph definition using navigation-compose and am using different viewModel for each of its screens. I'm doing
collectAsState
in the content parameter of
NavGraphBuilder.comoposable()
extension function. I want the respective Composable in the navgraph to be notified on any state changes in its associated viewModel. I checked every step in the process of mutating the state and viewModel state is working properly but the Composable is not listening to these changes and thus not being updated. How should this be achieved in general? Individual Composables listening to their own ViewModels when they're part of some navigation hierarchy like BottomNavigation ?
a

Adam Powell

12/04/2020, 3:34 PM
You get back a snapshot-observable
State<T>
and a
LaunchedEffect
collects the flow and writes into the state object. Compose sees the state changes and recomposes. Can you post the code that is behaving unexpectedly?
k

Kshitij Patil

12/04/2020, 4:12 PM
It's pretty rough and I'm afraid I won't be able to share the code. I can describe it a bit more: I've designed a form using multiple Composables, each asking one question and all share the same viewmodel. On pressing next, respective field from the state (immutable data class instance in a viewmodel) is updated. Third page among these needs some value from db so I'm doing a search and update for third page at the time of first page only. Now when I quickly navigate to the third page by tapping "Next", that value update isn't received and I'm left with the default one only. However, if I say wait for 3-4 seconds before navigating to the 3rd page, I get the updated value. I debugged the code a bit and found that, the db fetch that was supposed to happen only once (at the start) is actually called on every navigate call (probably because state is being mutated) so the value I fetched on the first page is lost on the third due to overwrite.
j

Joost Klitsie

12/05/2020, 7:22 AM
Well i am going to guess that you're using it wrongly. I am using collectasstate and it does exactly what it is supposed to do: it collects a flow and turns it into a state. It sounds to me you did not scope your viewmodels correctly and you are overriding values that are not supposed to be overridden. You probably should have 1 viewmodel that is scoped to the entire flow, and then per page a separate viewmodel. So the page viewmodels will control the page and information there and report their values and get their initial values to and from the main viewmodel
k

Kshitij Patil

12/05/2020, 8:18 AM
I'll post what worked for me and let me know the better way of doing it. So I was passing in the collected state to a Composable which was hosting
NavHost
and then I distributed the respective fields to composables in navgraph assuming that only those composables will be notified when respective field is changed. However, since the Composable itself was taking in the state, it turned out to be recomposed on any field changes. Instead of passing in state, I kept that at parent Composable only and used "slots" to write individual pages and passed in respective state fields directly into those slots. This way, only associated pages got recomposed and everything just worked. But, since I moved large chunk of code from the NavHost to parent itself in the form of slots, it resulted in verbose code in the same file.
4 Views