Compose Navigation - 导航目的地...不是此 NavGraph 的直接子项

Compose Navigation - navigation destination ... is not a direct child of this NavGraph

我正在尝试为我的订单管理应用构建以下导航:

manage_orders/manage_orders/{locationId}
manage_orders/manage_order_details/{orderId}

这是我的导航代码:

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)
            )
        }
    }
}

这里是开始导航的代码:

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) ?: ""
            )
        }
    }
}

但是,我遇到以下错误:

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.invoke(NavHost.kt:113)
    at androidx.navigation.compose.NavHostKt$NavHost.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.invoke(Wrapper.android.kt:144)
    at androidx.compose.ui.platform.WrappedComposition$setContent.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.invoke(Wrapper.android.kt:142)
    at androidx.compose.ui.platform.WrappedComposition$setContent.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)

这里有什么问题?

更新 1(根据 Ian 的解决方案)

@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))
            }
        }
    }
}

但仍然面临同样的问题。看起来我没能理解 Ian 的建议。我错过了什么?

这一行:

startDestination = LeafScreen.ManageOrders.createRoute(Screen.ManageOrders, locationId)

与您目的地的任何 route 参数都不匹配。例如,您的 Screen.ManageOrders 的路线是:

route = LeafScreen.ManageOrders.createRoute(root)

startDestination 需要 route 完全匹配 。这意味着您需要使用

startDestination = LeafScreen.ManageOrders.createRoute(root)

如果你想设置一个 locationId 用于你的起始目的地,你应该在你的参数上设置一个 defaultValue:

@ExperimentalCoroutinesApi
private fun NavGraphBuilder.addManageOrdersTopLevel(
    navController: NavHostController,
    locationId: String
) {
    navigation(
        route = Screen.ManageOrders.route,
        startDestination = LeafScreen.ManageOrders.createRoute(root)
    ) {
        addManageOrders(
            navController = navController,
            root = Screen.ManageOrders,
            locationId = locationId
        )
        addManageOrderDetails(navController = navController, root = Screen.ManageOrders)
    }
}

@ExperimentalCoroutinesApi
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))
            }
        }
    }
}