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

Compose Multiplatform中使用Navigation Compose传递JSON对象遇阻求方案

问题:Compose Multiplatform中Navigation Compose传递JSON对象跳转报错

尝试在Compose Multiplatform中通过Navigation Compose实现页面间对象传递,编写代码如下:

@Composable
fun DisneyApp(
    navController: NavHostController = rememberNavController()
) {
    NavHost(
        navController = navController,
        startDestination = HOME_ROUTE,
    ) {
        composable(route = HOME_ROUTE) {
            HomeScreen(onClick = { poster ->
                navController.navigate(
                    "${DETAIL_ROUTE}/${
                        Json.encodeToString(poster)
                    }"
                )
            })
        }
        composable(
            route = "${DETAIL_ROUTE}/{${DISNEY_KEY}}",
            arguments = listOf(
                navArgument(DISNEY_KEY) { type = NavType.StringType })
        ) { from ->
            from.arguments?.getString(DISNEY_KEY)?.let {
                DetailScreen(Json.decodeFromString<Poster>(it))
            }
        }
    }
}

点击列表项跳转详情页时抛出异常:

java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=android-app://androidx.navigation/detail/{"id":1,"name":"Toy Story 4","release":"2019","playtime":"1 h 40 min","description":"Toy Story 4 is a 2019 American computer-animated comedy film produced by Pixar Animation Studios for Walt Disney Pictures. It is the fourth installment in Pixar's Toy Story series and the sequel to Toy Story 3 (2010). It was directed by Josh Cooley (in his feature directorial debut) from a screenplay by Andrew Stanton and Stephany Folsom; the three also conceived the story alongside John Lasseter, Rashida Jones, Will McCormack, Valerie LaPointe, and Martin Hynes.[2] Tom Hanks, Tim Allen, Annie Potts, Joan Cusack, Wallace Shawn, John Ratzenberger, Estelle Harris, Blake Clark, Bonnie Hunt, Jeff Garlin, Kristen Schaal and Timothy Dalton reprise their character roles from the first three films. They are joined by Tony Hale, Keegan-Michael Key, Jordan Peele, Christina Hendricks, Keanu Reeves, and Ally Maki, who voice the new characters. The film also posthumously features Don Rickles, who appears through use of archived voice recordings.","plot":"Nine years earlier, following the events of Toy Story 2, Bo Peep and Woody attempt to rescue RC, Andy's remote-controlled car, from a rainstorm. Just as they finish the rescue, Woody watches as Bo is donated to a new owner, and considers going with her, but ultimately decides to remain with Andy. Years later, a teenage Andy donates them to Bonnie, a younger child, before he goes off to college. While the toys are grateful to have a new child, Woody struggles to adapt to an environment where he is not the favorite as he was with Andy, apparent when Bonnie takes Woody's sheriff badge and puts it on Jessie instead, not even bothering to give him a role during her playtime.","poster":"https://user-images.githubusercontent.com/24237865/75087934-5a53dc00-553e-11ea-94f1-494c1c68a574.jpg","gif":"https://media0.giphy.com/media/sgswHaZw5yklq/giphy.gif?cid=ecf05e473wd424bhp29tw5i4clg60djlvz4aridyzgxua96q&rid=giphy.gif&ct=g"} } cannot be found in the navigation graph ComposeNavGraph(0x0) startDestination={Destination(0x78d845ec) route=home}

此前在Android Compose中使用Gson结合Uri.encode的方案可正常运行,但Uri.encode在Compose Multiplatform环境中不可用,需要替代方案,同时寻求Navigation Compose传递JSON字符串对象的经验。

解决方案

报错原因

直接将JSON字符串放入路由参数中,JSON包含的{}、空格、/等特殊字符会破坏路由结构,Navigation会将这些字符解析为路由的层级部分,导致无法匹配预设的${DETAIL_ROUTE}/{${DISNEY_KEY}}路由规则,从而抛出找不到目标页面的异常。

方案一:使用跨平台URL编码工具(适配路由传参)

1. 添加跨平台编码依赖

在项目的build.gradle.kts中引入Ktor的工具库,它提供了跨平台的URL编码/解码方法:

implementation("io.ktor:ktor-utils:2.3.3") // 可替换为最新稳定版本

2. 修改跳转代码,编码JSON字符串

import io.ktor.util.encodeURLQueryComponent

@Composable
fun DisneyApp(
    navController: NavHostController = rememberNavController()
) {
    NavHost(
        navController = navController,
        startDestination = HOME_ROUTE,
    ) {
        composable(route = HOME_ROUTE) {
            HomeScreen(onClick = { poster ->
                val jsonStr = Json.encodeToString(poster)
                val encodedJson = jsonStr.encodeURLQueryComponent()
                navController.navigate("${DETAIL_ROUTE}/$encodedJson")
            })
        }
        // ...
    }
}

3. 修改详情页代码,解码字符串

import io.ktor.util.decodeURLQueryComponent

composable(
    route = "${DETAIL_ROUTE}/{${DISNEY_KEY}}",
    arguments = listOf(
        navArgument(DISNEY_KEY) { type = NavType.StringType })
) { backStackEntry ->
    backStackEntry.arguments?.getString(DISNEY_KEY)?.let { encodedJson ->
        val jsonStr = encodedJson.decodeURLQueryComponent()
        DetailScreen(Json.decodeFromString<Poster>(jsonStr))
    }
}

方案二:使用SavedStateHandle传递参数(更推荐)

无需将参数放入路由,直接通过Navigation的SavedStateHandle传递,避免路由解析问题:

1. 修改跳转逻辑

@Composable
fun DisneyApp(
    navController: NavHostController = rememberNavController()
) {
    NavHost(
        navController = navController,
        startDestination = HOME_ROUTE,
    ) {
        composable(route = HOME_ROUTE) {
            HomeScreen(onClick = { poster ->
                val jsonStr = Json.encodeToString(poster)
                navController.navigate(DETAIL_ROUTE) {
                    // 将参数存入SavedStateHandle
                    launchSingleTop = true
                    putExtra(DISNEY_KEY, jsonStr)
                }
            })
        }
        // ...
    }
}

2. 修改详情页路由与接收逻辑

composable(route = DETAIL_ROUTE) { backStackEntry ->
    // 从SavedStateHandle中获取参数
    val jsonStr = backStackEntry.savedStateHandle.get<String>(DISNEY_KEY)
    jsonStr?.let {
        DetailScreen(Json.decodeFromString<Poster>(it))
    }
}

这种方式更符合Navigation Compose的设计规范,尤其适合传递复杂对象,无需处理URL编码问题,跨平台兼容性更好。

内容的提问来源于stack exchange,提问作者Ali

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 06:54:56