Reputation: 2914
I'm using Compose TypeSafe navigation for my application.
This is one of the extension function called in NavHost
private fun NavGraphBuilder.loginNavigation(navController: NavHostController) {
composable<ScreenData.SplashData> {
SplashScreen(
viewModel = hiltViewModel(),
onAuthLogin = {
navController.navigate(ScreenData.HomeData) //Tab 1 screen (out of 3 Tabs in NavigationBar)
},
onUnAuthLogin = {
navController.navigate(ScreenData.PhoneData)
},
onAppUpdate = {
navController.navigate(ScreenData.AppUpdateData)
}
)
}
composable<ScreenData.PhoneData> {
PhoneScreen(
viewModel = hiltViewModel(),
onLoginSuccess = { number, hash ->
navController.navigate(ScreenData.SmsData(number, hash))
},
)
}
composable<ScreenData.SmsData> {
SmsScreen(
viewModel = hiltViewModel(),
onFirstLoginComplete = {
navController.navigate(ScreenData.WalkthroughData)
},
onLoginComplete = {
navController.navigate(ScreenData.HomeData) //Tab 1 screen (out of 3 Tabs in NavigationBar)
},
onBack = {
navController.navigate(ScreenData.PhoneData)
},
)
}
composable<ScreenData.WalkthroughData> {
WalkthroughScreen(
onComplete = {
navController.navigate(ScreenData.HomeData) //Tab 1 screen (out of 3 Tabs in NavigationBar)
},
)
}
}
Sometimes I use navController.popBackStack()
if I want to return back to the previous screen (and its not different one from which I navigated from).
ScreenData.PhoneData
Thats just ScreenData
Interface with data classes
for each screen (with optional payload data) - new typesafe navigation
Issue I have is that all the time I navigate with navController.navigate()
function, my ViewModel
init
is called and entire screen is recreated as new. I dont want this all the time. So if screen exists already (especially in Tabs - I have 3 tabs which user can switch between by clicking TabButtons there), I just want to show existing instance of that screen instead of recreating it all the time.
Is there any way how to manage this properly? This type of navigation is new so I can't find a lot of detail about how to use it properly without creating copies of screens within memory.
In terms of clean architecture I'm not passing NavHostController
into Composable
screens or ViewModel
, I would rather have it done by callbacks and manage entire navigation process between screens in single Navigation class.
I made this function:
fun navigateToSingleton(
navController: NavController,
destination: ScreenData,
) {
navController.navigate(destination) {
popUpTo(navController.graph.startDestinationId) {
inclusive = false // Keep the singleton destination in the backstack
saveState = true // Save state for the current backstack entry
}
launchSingleTop = true // Avoid duplicate destinations in the stack
restoreState = true // Restore previously saved state
}
}
This will restore state of my Composable with ViewModel but it glitches entire navigation process.
I use this function all the time I navigate to Tab screen
Tab1: ScreenData.HomeData
Tab2: ScreenData.ProfileData
Tab3: ScreenData.SettingData
But when I navigate from ScreenData.HomeData
-> ScreenData.PermissionData
(Permission management screen) and from this screen when I trigger onBack(gesture or button) -> navigateToSingleton(navController, ScreenData.SettingData)
. I end up in Setting Tab
which is okay. But then when I click Tab 1
which suppose to call navigateToSingleton(navController, ScreenData.HomeData)
, I end up in ScreenData.PermissionData
.
This navigation is complete mess and I cant understand it at all.
Upvotes: 0
Views: 85