I am using jetpack compose navigation in my app but I get IllegalArgumentException while trying to navigate to geoMarkerScreen from homeScreen. The problem seems at the BottomNavigationBar...How can I resolve this? I laready set up the NavHost

package com.example.bettehomes.navigation


    import androidx.compose.material3.NavigationBar
    import androidx.compose.material3.NavigationBarItem
    import androidx.compose.material3.Icon
    import androidx.compose.material3.Text
    import androidx.compose.runtime.Composable
    import androidx.compose.runtime.getValue
    import androidx.navigation.NavController
    import androidx.navigation.compose.currentBackStackEntryAsState
    
    
    @Composable
    fun BottomNavigationBar(navController: NavController) {
        NavigationBar {
            val navBackStackEntry by navController.currentBackStackEntryAsState()
            val currentRoute = navBackStackEntry?.destination?.route
    
            BottomNavItem.values().forEach { item ->
                NavigationBarItem(selected = currentRoute == item.route,
                    onClick = {
                        navController.navigate(item.route) {
                            popUpTo(navController.graph.startDestinationId) {
                                saveState = true
                            }
                            launchSingleTop = true
                            restoreState = true
                        }
                    }, icon = { Icon(item.icon, contentDescription = null) },label = { Text(item.label) })
                        }
        }

} 

The error appears to be at:

com.example.bettehomes.navigation.BottomNavigationBarKt$BottomNavigationBar$1$1$1.invoke(BottomNavigationBar.kt:23)
                                                                                                        at com.example.bettehomes.navigation.BottomNavigationBarKt$BottomNavigationBar$1$1$1.invoke(BottomNavigationBar.kt:21)

NavHost.kt:

package com.example.bettehomes.navigation

import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.example.bettehomes.data.login.AuthViewModel
import com.example.bettehomes.presentation.GeoMarkerViewModel
import com.example.bettehomes.presentation.authscreens.HomeScreen
import com.example.bettehomes.presentation.authscreens.LoginScreen
import com.example.bettehomes.presentation.authscreens.PrivacyPolicyScreen
import com.example.bettehomes.presentation.authscreens.SignUpScreen
import com.example.bettehomes.presentation.authscreens.TermsAndConditionsScreen
import com.example.bettehomes.presentation.authscreens.settings.SettingsScreen
import com.example.bettehomes.presentation.authscreens.splash.SplashScreen
import com.example.bettehomes.presentation.mapscreens.GeoMarkerScreen
import com.example.bettehomes.presentation.mapscreens.MapsScreen

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppNavigation(
    snackbarHostState: SnackbarHostState,
    geoMarkerViewModel: GeoMarkerViewModel,
    fetchLocationUpdates: () -> Unit,
    authViewModel: AuthViewModel = hiltViewModel()
) {
    val navController = rememberNavController()
    val isAuthenticated by authViewModel.isAuthenticated.collectAsState()
    Scaffold(
        bottomBar = {
            BottomNavigationBar(navController = navController)
        }
    ) {it
        NavHost(navController = navController, startDestination = Screens.SplashScreen) {
            composable(Screens.SplashScreen) {
                SplashScreen(openAndPopUp = { route, popUp ->
                    navController.navigateAndPopUp(route, popUp)
                })
            }
            composable(Screens.HomeScreen) {
                HomeScreen()
            }

            composable(Screens.MapScreen) {
                MapsScreen(
                    snackbarHostState = snackbarHostState,
                    navController = navController,
                    fetchLocationUpdates = fetchLocationUpdates
                )
            }

            composable(Screens.SignUpScreen) {
                SignUpScreen(navController)
            }
            composable(Screens.LoginScreen) {
                LoginScreen(navController)
            }
            composable(Screens.TermsAndConditions) {
                TermsAndConditionsScreen(navController)
            }
            composable(Screens.PrivacyPolicy) {
                PrivacyPolicyScreen(navController)
            }

            if (isAuthenticated) {
                composable(Screens.GeoMarkerScreen) {
                    GeoMarkerScreen(geoMarkerViewModel, navController)
                }
            } else {
                composable(Screens.LoginScreen) {
                    LoginScreen(navController)
                }
            }

            composable(Screens.SettingsScreen) {
                SettingsScreen(
                    restartApp = { route ->
                        navController.clearAndNavigate(
                            route,
                            startDestination = 1
                        )
                    },
                    openScreen = { route -> navController.navigate(route) }
                )
            }
        }
    }
}

BottomNavItem.kt:

package com.example.bettehomes.navigation

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Settings
import androidx.compose.ui.graphics.vector.ImageVector

enum class BottomNavItem(val route: String, val icon: ImageVector, val label: String) {
    Home("homeScreen", Icons.Default.Home, "Home"),
    Create("geoMarkerScreen", Icons.Default.Add, "Create"),
    Search("mapsScreen", Icons.Default.Search, "Search"),
    Settings("settingsScreen", Icons.Default.Settings, "Settings");
}
2

There are 2 best solutions below

2
Leviathan On

You can only navigate to a destination that you defined in your NavHost with the composable builder function. You define a Screens.GeoMarkerScreen route, so if you want to navigate to that screen, item.route in navController.navigate(item.route) must be exactly equal to whatever Screens.GeoMarkerScreen contains.

Since your question does not tell us what an item is or what its route property contains, I can only deduce from the exception that is thrown that it does not contain a valid navigation route. You can easly verify that by setting a breakpoint at that line and compare the actual content of item.route with Screens.GeoMarkerScreen.

0
Kaleab Woldemariam On

What worked was:

package com.example.bettehomes.navigation

import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.example.bettehomes.presentation.GeoMarkerViewModel
import com.example.bettehomes.presentation.authscreens.HomeScreen
import com.example.bettehomes.presentation.authscreens.LoginScreen
import com.example.bettehomes.presentation.authscreens.PrivacyPolicyScreen
import com.example.bettehomes.presentation.authscreens.SignUpScreen
import com.example.bettehomes.presentation.authscreens.TermsAndConditionsScreen
import com.example.bettehomes.presentation.authscreens.settings.SettingsScreen
import com.example.bettehomes.presentation.authscreens.splash.SplashScreen
import com.example.bettehomes.presentation.mapscreens.GeoMarkerScreen
import com.example.bettehomes.presentation.mapscreens.MapsScreen

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppNavigation(
    snackbarHostState: SnackbarHostState,
    geoMarkerViewModel: GeoMarkerViewModel,
    fetchLocationUpdates: () -> Unit,
    ) {
    val navController = rememberNavController()
    var isAuthenticated by remember { mutableStateOf(false)}
    Scaffold(
        bottomBar = {
            BottomNavigationBar(navController = navController)
        }
    ) {it
        NavHost(navController = navController, startDestination = Screens.SplashScreen) {
            composable(Screens.SplashScreen) {
                SplashScreen(openAndPopUp = { route, popUp ->
                    navController.navigateAndPopUp(route, popUp)
                })
            }
            composable(Screens.HomeScreen) {
                HomeScreen()
            }

            composable(Screens.MapScreen) {
                MapsScreen(
                    snackbarHostState = snackbarHostState,
                    navController = navController,
                    fetchLocationUpdates = fetchLocationUpdates
                )
            }

            composable(Screens.SignUpScreen) {
                SignUpScreen(navController)
            }
            composable(Screens.LoginScreen) {
                LoginScreen(navController)
            }
            composable(Screens.TermsAndConditions) {
                TermsAndConditionsScreen(navController)
            }
            composable(Screens.PrivacyPolicy) {
                PrivacyPolicyScreen(navController)
            }

            composable(Screens.GeoMarkerScreen) {
                GeoMarkerScreen(geoMarkerViewModel, navController) {
                    isAuthenticated = true }
            }

            composable(Screens.SettingsScreen) {
                SettingsScreen(
                    restartApp = { route ->
                        navController.clearAndNavigate(
                            route,
                            startDestination = 1
                        )
                    },
                    openScreen = { route -> navController.navigate(route) }
                )
            }
        }
    }
}