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