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

如何用ViewModel更新RecyclerView列表?井字棋实现疑问

井字棋对战历史记录实现分析与优化建议

现有实现的合理性

你的核心思路符合MVVM架构设计:用ViewModel持有LiveData管理对战结果数据,Fragment通过观察LiveData更新UI,职责划分清晰,这个方向是对的。但从代码细节来看,还有不少可以优化的地方:

具体优化点

1. LiveData集合更新逻辑问题

直接使用MutableLiveData<MutableList<*>>存在隐患:当你直接调用列表的add/remove等方法修改集合内容时,LiveData不会感知到内部变化,也就不会触发UI更新——因为LiveData仅监听引用的变更,而非集合内部元素的变化。

优化方案:
改用MutableLiveData<List<Result>>,每次添加新记录时创建新的列表实例,触发LiveData更新:

// GameViewModel 中
private val _results = MutableLiveData<List<Result>>(emptyList())
val results: LiveData<List<Result>> = _results

fun addGameResult(newResult: Result) {
    val updatedList = _results.value.orEmpty().toMutableList().apply {
        add(newResult)
    }
    _results.value = updatedList
}

也可以使用ObservableArrayList配合MediatorLiveData,自动监听集合内部变化。

2. 数据持久化缺失

当前实现仅将记录存在内存中,App重启后所有历史记录会丢失。如果需要持久化保存:

  • 简单场景:用SharedPreferences序列化结果列表(比如将Result转成JSON字符串存储)
  • 复杂场景:用Room数据库,支持结构化存储、排序、筛选,扩展性更强,适合后续功能迭代。

3. ViewModel职责拆分

如果GameViewModel同时负责游戏逻辑(落子、胜负判断)和历史记录管理,建议拆分出独立的GameHistoryViewModel,遵循单一职责原则,避免ViewModel过于臃肿。

4. RecyclerView更新效率优化

从Adapter代码来看,没有使用DiffUtil,当历史记录较多时,每次更新整个列表会造成不必要的UI重绘。建议实现DiffUtil.ItemCallback,让RecyclerView只更新变化的项:

class GameResultDiffCallback : DiffUtil.ItemCallback<Result>() {
    override fun areItemsTheSame(oldItem: Result, newItem: Result): Boolean {
        return oldItem.id == newItem.id // 假设Result有唯一ID字段
    }

    override fun areContentsTheSame(oldItem: Result, newItem: Result): Boolean {
        return oldItem == newItem
    }
}

然后在Adapter中使用ListAdapter替代普通RecyclerView.Adapter:

class GameHistoryAdapter : ListAdapter<Result, GameHistoryAdapter.ViewHolder>(GameResultDiffCallback()) {
    // ... 其余实现逻辑
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 05:33:11