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
相关产品推荐
相关产品推荐

