如何在Jetpack Compose中向其他Composable页面传递Data Class?
如何在Jetpack Compose导航中传递自定义Data Class实例?
方法一:通过Parcelable序列化传递(官方推荐)
这种方式贴合Jetpack Navigation的设计规范,将数据绑定到路由参数中,页面可独立获取参数。
1. 让Data Class实现Parcelable
给Holder类添加@Parcelize注解并实现Parcelable接口,确保所有属性支持序列化:
import android.os.Parcelable import kotlinx.parcelize.Parcelize @Parcelize data class Holder( val uri: String, val title: String, val desc: String, val source: String, val color: String? ) : Parcelable
2. 修改导航路由,添加参数占位符
在路由枚举中,为页面B的路由添加参数占位符:
enum class Screen(val route: String) { A("screen_a"), B("screen_b/{holder}") // 添加参数占位符 }
3. 页面A中导航时传递序列化数据
使用kotlinx-serialization将Holder序列化为JSON字符串,编码后拼接到路由中(需先添加依赖):
// 模块级build.gradle.kts plugins { id("kotlinx-serialization") } dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") }
修改页面A的导航逻辑:
@Composable fun A(navigateToScreenB: (Holder) -> Unit) { // 示例Holder实例 val sampleHolder = Holder("test_uri", "测试标题", "测试描述", "测试来源", "#ff0000") Button(onClick = { navigateToScreenB(sampleHolder) }) { Text("跳转至页面B") } } // 导航配置中Screen.A的部分 composable(route = Screen.A.route) { A( navigateToScreenB = { holder -> // 序列化并编码参数,避免特殊字符问题 val holderJson = Json.encodeToString(holder) val encodedJson = Uri.encode(holderJson) // 替换路由占位符并导航 navController.navigate(Screen.B.route.replace("{holder}", encodedJson)) } ) }
4. 页面B中解析参数
在导航配置中获取路由参数,解码并反序列化为Holder实例:
// 导航配置中Screen.B的部分 composable(route = Screen.B.route) { backStackEntry -> val encodedHolderJson = backStackEntry.arguments?.getString("holder") val holder = encodedHolderJson?.let { val decodedJson = Uri.decode(it) Json.decodeFromString<Holder>(decodedJson) } ?: run { // 参数为空时返回上一页 navController.popBackStack() return@composable } B(holder = holder) } @Composable fun B(holder: Holder) { // 使用传递过来的Holder数据 Column { Text(text = "标题:${holder.title}") Text(text = "描述:${holder.desc}") } }
方法二:使用共享ViewModel传递
如果数据结构复杂、不想做序列化,可通过共享ViewModel在页面间传递数据。
1. 创建共享ViewModel
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel class SharedHolderViewModel : ViewModel() { var holder: Holder? by mutableStateOf(null) }
2. 页面A中设置数据
@Composable fun A(navigateToScreenB: () -> Unit) { val viewModel = viewModel<SharedHolderViewModel>() val sampleHolder = Holder("test_uri", "测试标题", "测试描述", "测试来源", "#ff0000") Button(onClick = { viewModel.holder = sampleHolder navigateToScreenB() }) { Text("跳转至页面B") } } // 导航配置中Screen.A的部分 composable(route = Screen.A.route) { A( navigateToScreenB = { navController.navigate(Screen.B.route) } ) }
3. 页面B中获取数据
@Composable fun B() { val viewModel = viewModel<SharedHolderViewModel>() val holder = viewModel.holder ?: run { // 数据为空时返回上一页 navController.popBackStack() return@Composable } // 使用Holder数据 Column { Text(text = "标题:${holder.title}") Text(text = "描述:${holder.desc}") } } // 导航配置中Screen.B的部分 composable(route = Screen.B.route) { B() }
两种方法对比
- Parcelable序列化:遵循导航设计原则,数据与路由绑定,页面B可独立使用,适合大多数场景;缺点是需要处理序列化,复杂类可能需额外适配。
- 共享ViewModel:无需序列化,适合复杂数据或多页面共享状态的场景;缺点是数据与路由解耦,页面B依赖ViewModel状态,需处理数据为空的边界情况。
内容的提问来源于stack exchange,提问作者raazza
相关产品推荐
相关产品推荐

