julioromano
12/07/2022, 10:19 AMjulioromano
12/07/2022, 10:19 AMViewModel
but navigation actions must be invoked on the NavController
object which is inside the composition in the Activity
.
Since the lifecycle of the Activity
is shorter than that of the ViewModel
we can’t pass references to functions such as NavController.popUpToWelcomeScreen()
from the Activity
to the ViewModel
(besides the potential of memory leaks, we’ll loose the reference to the function any time the activity is recreated).
How to properly encapsulate conditional navigation using the pattern proposed in the video?Pablichjenkov
12/07/2022, 2:44 PM@Composable
fun LogoutScreen(accountViewModel: AccountViewModel) {
val loginStatus by accountViewModel.loginStatus.collectAsState()
when(loginStatus) {
LogIn -> { paintLogoutUI() }
LogOut -> { navController.navigate("WelcomePage") }
}
}
You don’t pass a reference from anywhere to the ViewModel, so the ViewModel invoke/callback later on, instead invert the flow. You request execution to the ViewModel and listen for the result of the execution. The ViewModel doesn;t know about its client, doesn’t call functions in its clientsIan Lake
12/07/2022, 4:18 PMColton Idle
12/07/2022, 6:35 PMjulioromano
12/12/2022, 3:21 PMNavHost
would allow its state to be hoisted so that we could directly manipulate it?
After all isn’t Jetpack Compose about manipulating hoisted state to trigger updates to the UI instead of having to manually change a `View`’s internal state by calling its setters?
Every time I do a navController.navigate()
I feel like I’m doing something like textView.setText()
.Ian Lake
12/12/2022, 4:06 PMnavigate
is just how you update the state of the NavController, just like how you call open
or close
on a DrawerState
Ian Lake
12/12/2022, 4:10 PMPablichjenkov
12/12/2022, 7:13 PMIan Lake
12/12/2022, 8:09 PMPablichjenkov
12/12/2022, 9:07 PMjulioromano
12/13/2022, 7:52 AMThere are quite a few composition state holders that can’t be hoisted out of composition safety though - ScrollState looks like it can be hoisted, but any attempt to change the state from a ViewModel actually just crashes..This opens the pandora’s box of architectural opinions: Should a given composable’s state be manageable by the ViewModel/BusinessLogic or should it be exclusive to the UI layer? I don’t think there’s a definitive answer for this. Take
ScrollState
for instance, in most cases most people would be okay with it being exclusive to the UI layer, so that the business logic can be agnostic about it and the UI will transparently take care of restoring the scroll position of a list.
But things change as soon as the business requirements say that the list must be programmatically scrolled to a certain position whenever a certain business operation has been completed. In this case we would like for the ScrollState
to be hoisted to our ViewModel/BusinessLogic to better control it.
So maybe it boils down to a matter of balancing “how complicated is it to make a certain state work out of the composition” with “how useful is it to actually be able to hoist a certain state out of the composition”.
IMHO (just my 2 cents that are worth much less than that 🙂 ) for ScrollState
the usefulness would be minimal, but for NavHost
I’d say quite the opposite.Colton Idle
12/13/2022, 9:08 AMNavController is already the hoisted state of the NavHost.🤯 @Manuel Vivo i guess this also goes hand in hand with how we talked about the fact that you can't actually hoist the state of a bottom sheet into a ViewModelis just how you update the state of the NavController, just like how you callnavigate
oropen
on aclose
DrawerState
Manuel Vivo
12/13/2022, 11:47 AMjulioromano
12/13/2022, 12:25 PMNavHost
falls in that caveat’s topic though, navController.navigate()
is not suspending.Pablichjenkov
12/13/2022, 2:03 PM