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

Compose中如何在页面间传递自定义模型并实现双向通信?

Compose页面间传递自定义模型与双向通信方案

1. 用共享ViewModel实现(最推荐)

ViewModel的生命周期独立于页面导航,很适合跨页面共享复杂数据,读写数据就能实现双向通信。

示例代码:

// 定义共享ViewModel,存储自定义模型
class SharedDataViewModel : ViewModel() {
    val customModel = MutableStateFlow<CustomModel?>(null)
}

// 发送页面
@Composable
fun SenderScreen(navController: NavHostController, viewModel: SharedDataViewModel) {
    val testModel = CustomModel(id = 1, name = "初始数据")
    Button(onClick = {
        // 把数据存入ViewModel后跳转
        viewModel.customModel.value = testModel
        navController.navigate("receiver")
    }) {
        Text("跳转到接收页")
    }
}

// 接收页面
@Composable
fun ReceiverScreen(navController: NavHostController, viewModel: SharedDataViewModel) {
    val currentModel by viewModel.customModel.collectAsState()
    currentModel?.let { model ->
        Column {
            Text("收到的数据:${model.name}")
            Button(onClick = {
                // 修改ViewModel中的数据,实现双向同步
                viewModel.customModel.value = model.copy(name = "已修改数据")
                navController.popBackStack()
            }) {
                Text("返回并更新数据")
            }
        }
    }
}

// 在NavHost中注入共享ViewModel
val sharedViewModel = viewModel<SharedDataViewModel>()
NavHost(navController = navController, startDestination = "sender") {
    composable("sender") {
        SenderScreen(navController, sharedViewModel)
    }
    composable("receiver") {
        ReceiverScreen(navController, sharedViewModel)
    }
}

2. 让自定义模型实现Parcelable,结合Bundle传递

如果只是单向传递复杂数据,可以让模型实现Parcelable接口,这样就能通过导航参数传递,也能适配SafeArgs的逻辑。

步骤:

  1. 给自定义模型添加Parcelable实现:
@Parcelize
data class CustomModel(val id: Int, val name: String) : Parcelable
  1. 定义带参数的路由:
NavHost(...) {
    composable(
        route = "receiver",
        arguments = listOf(
            navArgument("customModel") {
                type = ParcelableType(CustomModel::class.java)
            }
        )
    ) { backStackEntry ->
        val receivedModel = backStackEntry.arguments?.getParcelable<CustomModel>("customModel")
        ReceiverScreen(receivedModel)
    }
}
  1. 跳转时传递参数:
val model = CustomModel(id = 1, name = "测试数据")
navController.navigate("receiver") {
    arguments = bundleOf("customModel" to model)
}

注意:这种方式更适合单向传递,若需要双向通信,ViewModel的方案会更省心,毕竟返回时回传数据需要额外处理。

3. 用回调函数实现返回时的数据回传

如果只需要在从接收页返回时把修改后的数据带回去,可以给导航逻辑添加回调处理。

示例代码:

// 发送页面
@Composable
fun SenderScreen(navController: NavHostController) {
    var updatedModel by remember { mutableStateOf<CustomModel?>(null) }
    Button(onClick = {
        navController.navigateWithResult("receiver") { resultBundle ->
            updatedModel = resultBundle.getParcelable("updatedModel")
        }
    }) {
        Text("跳转到接收页")
    }
    updatedModel?.let {
        Text("返回的修改后数据:${it.name}")
    }
}

// 接收页面
@Composable
fun ReceiverScreen(navController: NavHostController) {
    val originalModel = CustomModel(id = 1, name = "初始数据")
    Button(onClick = {
        val resultBundle = bundleOf(
            "updatedModel" to originalModel.copy(name = "修改完成")
        )
        navController.popBackStackWithResult(resultBundle)
    }) {
        Text("返回并传递修改后的数据")
    }
}

// 给NavController添加扩展函数处理结果回调
fun NavController.navigateWithResult(route: String, onResult: (Bundle) -> Unit) {
    val callback = NavResultCallback(onResult)
    currentBackStackEntry?.savedStateHandle?.set("navResultCallback", callback)
    navigate(route)
}

fun NavController.popBackStackWithResult(result: Bundle) {
    val callback = previousBackStackEntry?.savedStateHandle?.get<NavResultCallback>("navResultCallback")
    callback?.onResult?.invoke(result)
    popBackStack()
}

// 实现Parcelable的回调类
class NavResultCallback(val onResult: (Bundle) -> Unit) : Parcelable {
    constructor(parcel: Parcel) : this(parcel.readSerializable() as (Bundle) -> Unit)

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeSerializable(onResult as java.io.Serializable)
    }

    override fun describeContents(): Int = 0

    companion object CREATOR : Parcelable.Creator<NavResultCallback> {
        override fun createFromParcel(parcel: Parcel): NavResultCallback = NavResultCallback(parcel)
        override fun newArray(size: Int): Array<NavResultCallback?> = arrayOfNulls(size)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 05:05:14