I am trying to build below navigation for my order management app:
manage_orders/manage_orders/{locationId}
manage_orders/manage_order_details/{orderId}
And here is my navigation code for that:
internal sealed class Screen(val route: String) {
object ManageOrders : Screen(manage_orders)
}
private sealed class LeafScreen(val route: String) {
fun createRoute(root: Screen): String {
return "${root.route}/$route"
}
object ManageOrders : LeafScreen("manage_orders/{locationId}") {
fun createRoute(root: Screen, locationId: String): String {
return "${root.route}/manage_orders/$locationId"
}
}
object ManageOrderDetails : LeafScreen("manage_order_details/{orderId}") {
fun createRoute(root: Screen, orderId: String): String {
return "${root.route}/manage_order_details/$orderId"
}
}
}
@ExperimentalCoroutinesApi
@Composable
internal fun AppNavigation(
navController: NavHostController,
locationId: String,
modifier: Modifier = Modifier
) {
NavHost(
navController = navController,
startDestination = Screen.ManageOrders.route,
modifier = modifier,
) {
addManageOrdersTopLevel(navController, locationId)
}
}
@ExperimentalCoroutinesApi
private fun NavGraphBuilder.addManageOrdersTopLevel(
navController: NavHostController,
locationId: String
) {
navigation(
route = Screen.ManageOrders.route,
startDestination = LeafScreen.ManageOrders.createRoute(Screen.ManageOrders, locationId)
) {
addManageOrders(navController = navController, root = Screen.ManageOrders)
addManageOrderDetails(navController = navController, root = Screen.ManageOrders)
}
}
@ExperimentalCoroutinesApi
private fun NavGraphBuilder.addManageOrders(
navController: NavHostController,
root: Screen
) {
composable(
route = LeafScreen.ManageOrders.createRoute(root),
arguments = listOf(
navArgument(LOCATION_ID) { type = NavType.StringType }
)
) { backStackEntry ->
backStackEntry.arguments?.let {
ManageOrders(locationId = it.getString(LOCATION_ID)!!) { orderId ->
navController.navigate(LeafScreen.ManageOrderDetails.createRoute(root, orderId))
}
}
}
}
@ExperimentalCoroutinesApi
private fun NavGraphBuilder.addManageOrderDetails(
navController: NavHostController,
root: Screen
) {
composable(
route = LeafScreen.ManageOrderDetails.createRoute(root),
arguments = listOf(
navArgument(ORDER_ID) { type = NavType.StringType }
)
) { backStackEntry ->
backStackEntry.arguments?.let {
ManageOrderDetails(
navController = navController,
orderId = it.getString(ORDER_ID)
)
}
}
}
And here is the code to start the navigation:
class ManageOrderActivity : AppCompatActivity() {
@ExperimentalCoroutinesApi
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
AppNavigation(
navController = navController,
locationId = intent.extras?.getString(KEY_LOCATION_ID) ?: ""
)
}
}
}
However, I am getting below error:
FATAL EXCEPTION: main
Process: io.chanse.locals.cerve.qa, PID: 18285
java.lang.IllegalArgumentException: navigation destination -1881727488 is not a direct child of this NavGraph
at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.kt:72)
at androidx.navigation.NavGraphNavigator.navigate(NavGraphNavigator.kt:49)
at androidx.navigation.NavController.navigateInternal(NavController.kt:189)
at androidx.navigation.NavController.navigate(NavController.kt:1491)
at androidx.navigation.NavController.onGraphCreated(NavController.kt:913)
at androidx.navigation.NavController.setGraph(NavController.kt:852)
at androidx.navigation.NavController.setGraph(NavController.kt:90)
at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(NavHost.kt:113)
at androidx.navigation.compose.NavHostKt$NavHost$4.invoke(NavHost.kt:112)
at androidx.compose.runtime.DisposableEffectImpl.onRemembered(Effects.kt:81)
at androidx.compose.runtime.CompositionImpl$RememberEventDispatcher.dispatchRememberObservers(Composition.kt:781)
at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:639)
at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:733)
at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:432)
at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:144)
at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:135)
at androidx.compose.ui.platform.AndroidComposeView.setOnViewTreeOwnersAvailable(AndroidComposeView.android.kt:727)
at androidx.compose.ui.platform.WrappedComposition.setContent(Wrapper.android.kt:135)
at androidx.compose.ui.platform.WrappedComposition.onStateChanged(Wrapper.android.kt:187)
at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.java:354)
at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.java:196)
at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:142)
at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:135)
at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(AndroidComposeView.android.kt:814)
at android.view.View.dispatchAttachedToWindow(View.java:22010)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:4291)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:4298)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:4298)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:4298)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:4298)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:4298)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:4298)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3135)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2618)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9971)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1010)
at android.view.Choreographer.doCallbacks(Choreographer.java:809)
at android.view.Choreographer.doFrame(Choreographer.java:744)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:995)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8512)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1139)
What's the problem here?
Update 1 (as per Ian's solution)
@Composable
internal fun AppNavigation(
navController: NavHostController,
locationId: String,
modifier: Modifier = Modifier
) {
NavHost(
navController = navController,
startDestination = LeafScreen.ManageOrders.route,
modifier = modifier,
) {
addManageOrdersTopLevel(navController, locationId)
}
}
@ExperimentalCoroutinesApi
private fun NavGraphBuilder.addManageOrdersTopLevel(
navController: NavHostController,
locationId: String
) {
navigation(
route = Screen.ManageOrders.route,
startDestination = LeafScreen.ManageOrders.createRoute(Screen.ManageOrders)
) {
addManageOrders(
navController = navController,
root = Screen.ManageOrders,
locationId = locationId
)
}
}
private fun NavGraphBuilder.addManageOrders(
navController: NavHostController,
root: Screen,
locationId: String
) {
composable(
route = LeafScreen.ManageOrders.createRoute(root),
arguments = listOf(
navArgument(LOCATION_ID) {
type = NavType.StringType
defaultValue = locationId
}
)
) { backStackEntry ->
backStackEntry.arguments?.let {
ManageOrders(locationId = it.getString(LOCATION_ID)!!) { orderId ->
navController.navigate(LeafScreen.ManageOrderDetails.createRoute(root, orderId))
}
}
}
}
But still facing the same issue. Look's like I failed to understand what Ian sggested. What have I missed?