Jetpack Compose组件间数据共享问题:ProfileScreen无法获取数据
问题根源
- ViewModel实例不共享:在
EmployeeSettingsViewModel中,你手动通过SharedViewModel(employeeSettingsModel)创建了ViewModel实例,这会完全绕过Hilt的依赖注入管理,导致这个实例和BottomNavigationScreen、ProfileScreen中通过hiltViewModel()获取的SharedViewModel不是同一个对象——两边操作的是不同内存空间,数据自然无法同步。 - 数据更新逻辑无效:由于操作的是独立的ViewModel实例,你在
EmployeeSettingsViewModel中调用setSharedData时,修改的只是本地新建实例的 data,而非全局共享的那个。
解决步骤与代码修正
1. 修正EmployeeSettingsViewModel:通过Hilt注入SharedViewModel
删除手动实例化代码,改为构造函数注入SharedViewModel,确保使用同一全局实例:
@HiltViewModel class EmployeeSettingsViewModel @Inject constructor( employeeSettingsModel: EmployeeSettingsModel, private val commonViewModel: CommonViewModel, private val authRepository: AuthRepository, private val realtimeDatabaseViewModel: RealTimeDatabaseViewModel, private val cypherInstance: CryptoClass, // 注入SharedViewModel,替代手动实例化 private val sharedViewModel: SharedViewModel ) : ViewModel() { companion object { private const val TAG = "EmployeeSettingsViewModel" private val SECURITYLIST = listOf("phoneNumber", "email", "age", "name") } private val _uiState = MutableStateFlow(employeeSettingsModel) val uiState: StateFlow<EmployeeSettingsModel> = _uiState.asStateFlow() fun setSharedData(employeeSettingsModel: EmployeeSettingsModel) { sharedViewModel.setSharedData(employeeSettingsModel) } ... }
2. 确保SharedViewModel的全局单例作用域
为让多个屏幕共享同一实例,给SharedViewModel添加@Singleton注解,Hilt会确保整个应用生命周期内只有一个实例:
@HiltViewModel @Singleton class SharedViewModel @Inject constructor( employeeSettingsModel: EmployeeSettingsModel ) : ViewModel() { private val _sharedData = MutableStateFlow(employeeSettingsModel) val sharedData: StateFlow<EmployeeSettingsModel> get() = _sharedData.asStateFlow() fun setSharedData(data: EmployeeSettingsModel) { // 修正打印逻辑,打印更新后的data字段 println("SharedViewModel: ${data.country}") _sharedData.value = data } }
3. 确保数据同步触发
在EmployeeSettingsScreen中,完成EmployeeSettingsModel更新后,必须调用employeeSettingsViewModel.setSharedData(updatedModel),将最新数据同步到SharedViewModel:
@Composable fun EmployeeSettingsScreen() { val employeeSettingsViewModel: EmployeeSettingsViewModel = hiltViewModel() val commonViewModel: CommonViewModel = hiltViewModel() val commonUiState: CommonModel by commonViewModel.uiState.collectAsState() val uiState by employeeSettingsViewModel.uiState.collectAsState() // 示例:用户提交表单时同步数据到SharedViewModel Button(onClick = { val updatedModel = uiState.copy( name = "新名字", email = "new@email.com" // 其他字段更新逻辑 ) employeeSettingsViewModel.setSharedData(updatedModel) }) { Text("保存并同步到Profile") } ... }
4. 验证ProfileScreen的数据收集
ProfileScreen代码无需大改,确保通过hiltViewModel()获取全局单例的SharedViewModel即可:
@Composable fun ProfileScreen() { val sharedViewModel: SharedViewModel = hiltViewModel() val sharedData by sharedViewModel.sharedData.collectAsState() val commonViewModel: CommonViewModel = hiltViewModel() val uiState by when (LoggedInUser.registrationType.value) { "employee" -> sharedViewModel.sharedData else -> throw IllegalStateException("Invalid user type") }.collectAsState() LaunchedEffect(sharedData) { println("The sharedData is currently $sharedData") } // 用sharedData渲染UI Column { Text("姓名:${sharedData.name}") Text("邮箱:${sharedData.email}") } ... }
补充说明
如果仅需在BottomNavigationScreen下的子页面间共享数据,而非全局共享,可以不用@Singleton,而是在获取ViewModel时指定NavGraph作用域:
// 在BottomNavigationScreen中获取NavGraph作用域的ViewModel val sharedViewModel: SharedViewModel = hiltViewModel(navController.graph) // 在子页面(EmployeeSettingsScreen、ProfileScreen)中同样使用NavGraph作用域获取 val sharedViewModel: SharedViewModel = hiltViewModel(navController = rememberNavController())
这种方式更符合组件化的作用域管理,避免全局单例的过度使用。
内容的提问来源于stack exchange,提问作者Lazza
相关产品推荐
相关产品推荐

