Compose中多DiceView共用ViewModel实例问题的解决咨询
解决单Activity+Compose架构下多个组件共享ViewModel实例的问题
方案1:给每个ViewModel实例指定唯一Key(基于Hilt)
通过给hiltViewModel()传入唯一的key参数,让Hilt为每个DiceView创建独立的DiceViewModel实例。
GameScreen 调整
@Composable fun GameScreen() { Column( modifier = Modifier .padding(32.dp), verticalArrangement = Arrangement.Center ) { // 给每个DiceView传入唯一标识作为key repeat(5) { index -> DiceView(diceKey = "dice_$index") } } }
DiceView 调整
@Composable fun DiceView( diceKey: String, viewModel: DiceViewModel = hiltViewModel(key = diceKey) ) { val state = viewModel.state.value Log.i("XX", System.identityHashCode(viewModel).toString()) Log.i("XX", LocalViewModelStoreOwner.current.toString()) Dice(viewModel = viewModel, state = state) }
原理:hiltViewModel()的key参数会让Hilt在同一个ViewModelStoreOwner(当前页面的NavBackStackEntry)下,根据不同key存储和获取不同的ViewModel实例,实现每个DiceView拥有独立的ViewModel。
方案2:状态提升到父组件(架构优化方案)
如果不需要每个骰子单独持有ViewModel,可将所有骰子的状态统一管理在父级GameViewModel中,通过状态提升实现独立控制:
1. 创建GameViewModel
@HiltViewModel class GameViewModel @Inject constructor() : ViewModel() { private val _diceStates = MutableStateList<DiceState>() val diceStates: List<DiceState> = _diceStates init { // 初始化5个骰子的初始状态 repeat(5) { _diceStates.add(DiceState(eyes = 1)) } } fun rollDice(index: Int) { val newEyes = (1..6).random() _diceStates[index] = _diceStates[index].copy(eyes = newEyes) } }
2. 修改GameScreen和DiceView
@Composable fun GameScreen( viewModel: GameViewModel = hiltViewModel() ) { Column( modifier = Modifier .padding(32.dp), verticalArrangement = Arrangement.Center ) { viewModel.diceStates.forEachIndexed { index, state -> Dice( state = state, onRoll = { viewModel.rollDice(index) } ) } } } @Composable fun Dice( state: DiceState, onRoll: () -> Unit ) { Button(onClick = onRoll) { Text(text = state.eyes.toString()) } }
这种方案符合Compose状态管理最佳实践,将状态集中管理,避免多个ViewModel分散维护状态,同时解决同步变化问题。
内容的提问来源于stack exchange,提问作者wrYch
相关产品推荐
相关产品推荐

