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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 14:27:23