Enol Simón
07/03/2024, 9:17 PMnavigateUp(). I expect to not have to load the data again in Screen A as the data in the view model is persisted.Ian Lake
07/03/2024, 9:20 PMColton Idle
07/03/2024, 11:18 PMJakub Legindi
07/04/2024, 12:26 AMIan Lake
07/04/2024, 12:50 AMEnol Simón
07/04/2024, 8:28 AMNavHost (let's call it MainNavController) that includes a ModalNavigationDrawer, let's call it ScreenContainer, and then I have at the same lavel all the screens that are supposed to be detail screens, let's all them Screen B and Screen C
val mainNavController = rememberNavController()
val navigateTo: (uri: String) -> Unit = remember { { uri -> navigate(mainNavController, uri) } }
val goBack: () -> Boolean = remember { mainNavController::navigateUp }
NavHost(navController = mainNavController, startDestination = "Screen Container") {
composable(route = "Screen B") {
ScreenB(navigateBack = goBack)
}
composable(route = "Screen C") {
ScreenC(navigateBack = goBack)
}
composable(route = "Screen Container") {
val vm: ContainerViewModel = koinInject()
val uiState by vm.uiState.collectAsStateWithCurrentLifecycle()
val contentNavController = rememberNavController()
LaunchedEffect("InitScreenContainer") {
vm.initData()
}
ScreenContainer(
contentNavController = contentNavController,
uiState = uiState,
...
navigate = navigateTo,
)
}
}
}
The thing is that ScreenContainer contains a ModalNavigationDrawer, an ActionBar and inside, the content, which is another NavHost (let's call it ContentNavController) with few screens, let's call them Screen A1 and Screen A2. This screens are rendered when using the Navigation Drawer menu, inside the internal `NavHost`(ContentNavController)
ScreenContainer(contentNavController: NavHostController, navigate: (uri: String) -> Unit, ...) {
Scaffold(topBar = { ... }) {
NavHost(
navController = navController,
startDestination = "Screen A1",
) {
composable(route = "Screen A1") {
ScreenA1(navigate = navigate)
}
composable(route = "Screen A2") {
ScreenA2(navigate = navigate)
}
}
}
}
The viewmodels of the screens are hosted inside the composable like this:
ScreenA1(...) {
val vm: ScreenA1ViewModel = koinInject()
...
}
So now, let's say that in the MainNavController I am in ScreenContainer which internally, in the ContentNavController is in Screen A1
I navigate from Screen A1 to Screen A2 in the ContentNavController . From the Screen A2 I navigate to Screen B in the MainNavController
We have in this case two stacks:
• MainNavController: ScreenContainer > Screen B
• ContentNavController: Screen A1 > Screen A2
My expectations when I navigateUp() from Screen B is that I am back in ScreenContainer with the Screen A2 inflated, and Screen A2 has the data loaded inside.
My current status is that when I navigateUp() from Screen B , I am back in ScreenContainer with the Screen A2 inflated, but the Viewmodel is re instantiated.
I know it can be difficult to understand, thank you for your help in advance, any suggestion in how to simplify my current logic is welcome, I understand that is difficult without seeing the actual code though.Stylianos Gakis
07/04/2024, 8:36 AMsaveState = true, and when you come back do restoreState = true, and you will have all the same functionality without the nested NavHost which is definitely not really a good idea most of the times.
What am I missing here which does not let you do that?
edit: Oh, is is that this separate NavHost lives inside a drawer? 👀Enol Simón
07/04/2024, 8:49 AMScreen A1 and Screen A2 are inside the NavigationDrawer and the action bar. While Screen B and Screen C are OVER the navigation drawer and they have their own ActionBar with the navigation back button, instead opening the NavigationDrawer. That's why I have the nested NavHost.
To explain it in an old school way, Screen A1 and Screen A2 "are fragments" inside one activity, and Screen B and Screen C "are different activities".Stylianos Gakis
07/04/2024, 8:51 AMEnol Simón
07/04/2024, 9:00 AMIan Lake
07/04/2024, 6:13 PMLaunchedEffect("InitScreenContainer") {
vm.initData()
}
This is what is force reloading your data every time you come back to the screenIan Lake
07/04/2024, 6:15 PMColton Idle
07/05/2024, 3:43 AMinit or a by lazy
Technically... Could you have a launchEffect keyed on the VM?Ian Lake
07/05/2024, 3:44 AMLaunchedEffect is going to rerun when it re-enters composition - that's the exact problem hereColton Idle
07/05/2024, 3:46 AMIan Lake
07/05/2024, 3:46 AMIan Lake
07/05/2024, 3:48 AMstateIn + WhileSubscribed is generally what you should reach for 99% of the time - repositories deliver cold flows of information, your ViewModel caches those flows with stateIn, then your UI collects those when it enters compositionEnol Simón
07/08/2024, 4:06 PM