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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 15:48:03