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

Kotlin跨屏幕传值问题:选中客户数据无法在目标页面显示

问题原因与解决方案

问题根源

你遇到的核心问题是SharedViewModel在两个页面中是不同实例:默认情况下hiltViewModel()会将ViewModel与当前页面的NavBackStackEntry绑定,导致AddPeminjamanScreen和SelectCustomerScreen各自创建独立的SharedViewModel实例。因此在Select页面设置的数据,在Add页面无法读取到。

修复步骤

1. 修改导航代码,共享ViewModel实例

在AppNavigation.kt中,获取SharedViewModel时指定作用域为整个导航图的ViewModelStoreOwner,确保两个页面使用同一个实例:

// Fragment AddPeminjamanScreen
composable(
    route = Screens.AddPeminjamanScreen.name
) {
    // 指定导航图级别的ViewModel作用域
    val sharedViewModel: SharedViewModel = hiltViewModel(navController.viewModelStoreOwner)
    AddPeminjamanScreen(navController, sharedViewModel)
}

// Fragment SelectCustomerScreen
composable(
    route = Screens.SelectCustomerScreen.name
) {
    val viewModel: CustomerViewModel = hiltViewModel()
    // 同样指定导航图级别的ViewModel作用域
    val sharedViewModel: SharedViewModel = hiltViewModel(navController.viewModelStoreOwner)

    SelectCustomerScreen(
        navController = navController,
        viewModel = viewModel,
        sharedViewModel = sharedViewModel
    )
}

2. 调整页面Composable的参数

移除页面中SharedViewModel的默认值,确保使用导航层传入的共享实例:

SelectCustomerScreen.kt

@Composable
fun SelectCustomerScreen(
    navController: NavHostController,
    viewModel: CustomerViewModel = hiltViewModel(),
    sharedViewModel: SharedViewModel // 移除默认值,强制使用传入的共享实例
) {
    LazyColumn {
        // 假设viewModel中有客户列表数据,替换为你实际的数据源
        items(viewModel.customerList) { item ->
            EachRowSelectCustomer(
                navController = navController,
                itemState = item,
                sharedViewModel = sharedViewModel
            )
        }
    }
}

// EachRowSelectCustomer代码保持不变
fun EachRowSelectCustomer(
    navController: NavHostController,
    itemState: CustomerModel,
    sharedViewModel: SharedViewModel
) {
    Column {
        Row(
            modifier = Modifier
                .clickable(
                    interactionSource = remember { MutableInteractionSource() },
                    indication = rememberRipple(bounded = true)
                ) {
                    sharedViewModel.setSelectedCustomer(itemState)
                    navController.navigateUp()
                }
        ) {
            Text(text = itemState.item?.namaCustomer!!)
        }
    }
}

AddPeminjamanScreen.kt

@Composable
fun AddPeminjamanScreen(
    navController: NavHostController,
    sharedViewModel: SharedViewModel // 移除默认值,使用传入的共享实例
) {
    val selectedCustomer by sharedViewModel.selectedCustomer.collectAsState()

    // 使用LaunchedEffect监听状态变化,打印最新数据
    LaunchedEffect(selectedCustomer) {
        Log.d("AddPeminjamanScreen", "Selected Customer: ${selectedCustomer?.item?.namaCustomer}")
    }

    Row(
        modifier = Modifier
            .clickable(
                interactionSource = remember { MutableInteractionSource() },
                indication = rememberRipple(bounded = true)
            ) {
                navController.navigate(Screens.SelectCustomerScreen.name)
            }
    ) {
        Text(
            text = selectedCustomer?.item?.namaCustomer ?: "Select"
        )
    }
}

关键说明

  • 通过navController.viewModelStoreOwner指定ViewModel作用域后,SharedViewModel会在整个导航图中保持唯一实例,数据可以跨页面同步。
  • LaunchedEffect(selectedCustomer)会在选中客户数据变化时触发,确保日志能打印最新值(直接在Composable根节点的Log只会打印初始值)。

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

相关产品推荐
方舟 Agent Plan

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

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