You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose导航图间数据传递失败,求解决方案

Jetpack Compose导航图间数据传递失败问题

我需要在Jetpack Compose的导航图之间传递数据,以下是我的实现代码:

const val vitaminGraphRoutePattern = "vitamin_graph"
const val vitaminRoute = "vitamin_route"

fun NavController.navigateToVitamin(
    managerToken: String,
    managerId: Int,
    navOptions: NavOptions? = null
) {
    Log.d("vitamin", "navigateToVitamin: $managerToken, $managerId")

    this.navigate(
        route = "$vitaminGraphRoutePattern/$vitaminRoute?$MANAGER_TOKEN=$managerToken&$MANAGER_ID=$managerId",
        navOptions
    )
}

@OptIn(ExperimentalAnimationApi::class)
fun NavGraphBuilder.vitaminGraph(
    nestedGraphs: NavGraphBuilder.() -> Unit
) {
    navigation(
        route = vitaminGraphRoutePattern,
        startDestination = vitaminRoute,
    ) {
        nestedGraphs()
    }
}

@OptIn(ExperimentalAnimationApi::class)
fun NavGraphBuilder.vitaminScreen(
    moveToWelcomeSurvey: (surveyToken: String, answerData: QuestionAnswerData, managerToken: String, managerId: Int) -> Unit,
    moveToResult: (surveyToken: String, managerToken: String, managerId: Int) -> Unit
) {
    composable(
        route = "$vitaminRoute?" +
                "$MANAGER_TOKEN=${MANAGER_TOKEN}" +
                "&$MANAGER_ID=${MANAGER_ID}",
        arguments = listOf(
            navArgument(MANAGER_TOKEN) {
                type = NavType.StringType
                defaultValue = "no value"
            },
            navArgument(MANAGER_ID) {
                type = NavType.IntType
                defaultValue = -1
            }
        )
    ) { backStackEntry ->
        VitaminRoute(
            moveToWelcomeSurvey = { surveyToken, answerData ->
                moveToWelcomeSurvey(
                    surveyToken,
                    answerData,
                    backStackEntry.arguments?.getString(MANAGER_TOKEN) ?: "",
                    backStackEntry.arguments?.getInt(MANAGER_ID) ?: -1
                )
            },
            moveToResult = { surveyToken ->
                moveToResult(
                    surveyToken,
                    backStackEntry.arguments?.getString(MANAGER_TOKEN) ?: "",
                    backStackEntry.arguments?.getInt(MANAGER_ID) ?: -1
                )
            }
        )
    }
}

我尝试了以下两种导航写法,但均未成功,也尝试修改vitaminGraph的查询参数,依然无效:

写法1:

this.navigate(
    route = "$vitaminGraphRoutePattern?$MANAGER_TOKEN=$managerToken&$MANAGER_ID=$managerId",
    navOptions
)

写法2:

this.navigate(
    route = "$vitaminGraphRoutePattern/$vitaminRoute?$MANAGER_TOKEN=$managerToken&$MANAGER_ID=$managerId",
    navOptions
)

请问该如何解决此问题?


问题分析与修复方案

核心问题在于导航图(navigation组件)无法直接持有查询参数,且目标页面的路由参数占位符格式错误,导致参数无法被正确解析传递。

1. 修正路由参数占位符错误

在vitaminScreen的composable路由定义中,你错误地将参数常量本身作为占位符值:

// 错误写法
route = "$vitaminRoute?" +
        "$MANAGER_TOKEN=${MANAGER_TOKEN}" +
        "&$MANAGER_ID=${MANAGER_ID}"

正确的参数占位符格式应为{参数名},这样导航组件才能识别并解析传递的参数值。

2. 正确传递参数到目标页面

导航图仅作为页面分组容器,参数需要直接传递到其起始目标页面(即vitaminRoute),导航图会自动跳转到起始页并携带参数。

修正后的完整代码

导航扩展函数

const val vitaminGraphRoutePattern = "vitamin_graph"
const val vitaminRoute = "vitamin_route"
const val MANAGER_TOKEN = "manager_token"
const val MANAGER_ID = "manager_id"

fun NavController.navigateToVitamin(
    managerToken: String,
    managerId: Int,
    navOptions: NavOptions? = null
) {
    Log.d("vitamin", "navigateToVitamin: $managerToken, $managerId")
    // 直接导航到vitaminRoute,携带参数,导航图自动处理起始页跳转
    this.navigate(
        route = "$vitaminGraphRoutePattern/$vitaminRoute?$MANAGER_TOKEN=$managerToken&$MANAGER_ID=$managerId",
        navOptions
    )
}

导航图定义

@OptIn(ExperimentalAnimationApi::class)
fun NavGraphBuilder.vitaminGraph(
    nestedGraphs: NavGraphBuilder.() -> Unit
) {
    navigation(
        route = vitaminGraphRoutePattern,
        startDestination = vitaminRoute,
    ) {
        nestedGraphs()
    }
}

目标页面定义

@OptIn(ExperimentalAnimationApi::class)
fun NavGraphBuilder.vitaminScreen(
    moveToWelcomeSurvey: (surveyToken: String, answerData: QuestionAnswerData, managerToken: String, managerId: Int) -> Unit,
    moveToResult: (surveyToken: String, managerToken: String, managerId: Int) -> Unit
) {
    composable(
        // 修正参数占位符格式
        route = "$vitaminRoute?$MANAGER_TOKEN={$MANAGER_TOKEN}&$MANAGER_ID={$MANAGER_ID}",
        arguments = listOf(
            navArgument(MANAGER_TOKEN) {
                type = NavType.StringType
                defaultValue = "no value"
            },
            navArgument(MANAGER_ID) {
                type = NavType.IntType
                defaultValue = -1
            }
        )
    ) { backStackEntry ->
        // 安全获取参数并复用
        val token = backStackEntry.arguments?.getString(MANAGER_TOKEN) ?: "no value"
        val id = backStackEntry.arguments?.getInt(MANAGER_ID) ?: -1

        VitaminRoute(
            moveToWelcomeSurvey = { surveyToken, answerData ->
                moveToWelcomeSurvey(surveyToken, answerData, token, id)
            },
            moveToResult = { surveyToken ->
                moveToResult(surveyToken, token, id)
            }
        )
    }
}

额外优化建议

  • 可以将参数设置为可空,避免使用默认值:
    navArgument(MANAGER_TOKEN) {
        type = NavType.StringType
        nullable = true
    }
    
    获取参数时直接用backStackEntry.arguments?.getString(MANAGER_TOKEN)即可。
  • 使用Uri构建路由,避免字符串拼接错误:
    val route = Uri.parse("$vitaminGraphRoutePattern/$vitaminRoute")
        .buildUpon()
        .appendQueryParameter(MANAGER_TOKEN, managerToken)
        .appendQueryParameter(MANAGER_ID, managerId.toString())
        .build()
        .toString()
    this.navigate(route, navOptions)
    

内容的提问来源于stack exchange,提问作者c-an

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 06:20:16