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

RecyclerView数据未更新:批量修改unit属性后界面无反馈

问题描述

我正在实现一个功能,通过切换按钮批量修改RecyclerView列表项的unit属性。项目采用MVVM架构,业务逻辑在Repository层执行。经调试确认,Repository中List内所有item的unit已成功修改,但为ViewModel的_items.value赋值后,界面仍无变化,无法确定问题所在。


相关代码

WorkoutSetInfo

data class WorkoutSetInfo(
    @PrimaryKey(autoGenerate = true)
    val id: Long = 0,
    val set: Int,
    var weight: String = "0",
    var reps: String = "0",
    var unit: WorkoutUnit = WorkoutUnit.kg,
    val parentWorkoutId: Long = 0
)

Repository

class WriteDetailRepository(val dao: WorkoutDao) {
    private var setInfoList = arrayListOf(WorkoutSetInfo(set = 1)) // fixed set 1
    private var updatedList = listOf<WorkoutSetInfo>()
                get() = setInfoList.toList()

    fun changeUnit(unit: WorkoutUnit) {
        updatedList = setInfoList.map { setInfo ->
            setInfo.copy(unit = unit)
        }
    }

    fun add() {
        val item = WorkoutSetInfo(set = setInfoList.size + 1)
        setInfoList.add(item)
        updatedList = setInfoList.toList()
    }
    
    fun getList() : List<WorkoutSetInfo> = updatedList
}

ViewModel

class WriteDetailViewModel(
    private val repository: WriteDetailRepository
    ): ViewModel() {

    private var _items: MutableStateFlow<List<WorkoutSetInfo>> = MutableStateFlow(repository.getList())
    val items = _items.asStateFlow()

    fun changeUnit(unit: WorkoutUnit) {
        repository.changeUnit(unit)
        _items.value = repository.getList()
    }

    fun addSet() {
        viewModelScope.launch(Dispatchers.IO) {
            repository.add()
            _items.value = repository.getList() // here
        }
    }
}

Fragment

class WriteDetailFragment :  Fragment() {
    
    ...
    private val viewModel: WriteDetailViewModel by viewModels {
        WriteDetailViewModelFactory(
            (requireActivity().application as WorkoutApplication).writeDetailRepo
        )
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        _binding = FragmentWriteDetailBinding.inflate(inflater, container, false)

        binding.apply {
            ...
            
            addSet.setOnClickListener {
                viewModel.addSet()
            }

          
            unitToggle.addOnButtonCheckedListener { _, checkedId, isChecked ->
                if(isChecked) {
                    when(checkedId) {
                        R.id.kg -> viewModel.changeUnit(WorkoutUnit.kg)
                        R.id.lb -> viewModel.changeUnit(WorkoutUnit.lbs)
                    }
                }
            }
        }

        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.items.collect { list -> // list value does not change
                    adapter.submitList(list)
                }
            }
        }
    }
}

问题分析与修复

核心问题

Repository中updatedList的自定义getter逻辑导致了问题:你在changeUnit里给updatedList赋值了修改后的新列表,但updatedList的getter被硬编码为返回setInfoList.toList()——也就是原始未修改的列表副本,后续调用getList()时,拿到的始终是原始数据,ViewModel和界面自然感知不到变化。

修复方案

方案1:移除自定义getter,直接维护更新后的列表

修改Repository逻辑,确保getList()返回真正修改后的列表:

class WriteDetailRepository(val dao: WorkoutDao) {
    private var setInfoList = arrayListOf(WorkoutSetInfo(set = 1))
    private var updatedList: List<WorkoutSetInfo> = setInfoList.toList()

    fun changeUnit(unit: WorkoutUnit) {
        updatedList = setInfoList.map { setInfo ->
            setInfo.copy(unit = unit)
        }
    }

    fun add() {
        val item = WorkoutSetInfo(set = setInfoList.size + 1)
        setInfoList.add(item)
        updatedList = setInfoList.toList()
    }
    
    fun getList() : List<WorkoutSetInfo> = updatedList
}

方案2:简化逻辑,直接修改原列表(更简洁)

利用data class的copy()方法直接更新原列表元素,无需额外维护updatedList:

class WriteDetailRepository(val dao: WorkoutDao) {
    private val setInfoList = mutableListOf(WorkoutSetInfo(set = 1))

    fun changeUnit(unit: WorkoutUnit) {
        setInfoList.replaceAll { it.copy(unit = unit) }
    }

    fun add() {
        val item = WorkoutSetInfo(set = setInfoList.size + 1)
        setInfoList.add(item)
    }
    
    fun getList() : List<WorkoutSetInfo> = setInfoList.toList()
}

额外优化建议

  • changeUnit方法仅做内存操作,无需放在Dispatchers.IO线程执行,ViewModel中可直接调用
  • 确保RecyclerView的Adapter正确实现DiffUtil,让submitList能精准识别列表变化并更新界面

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 21:35:17