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

Fragment返回后数据持久化异常:新建详情页残留旧列表数据

问题:新建详情页残留旧列表数据

重复执行详情页添加列表项并完成的流程时,新建的Detail Fragment会残留之前的列表数据。比如之前详情页创建了3条列表项,新详情页添加数据时,会在已有3条数据的基础上新增内容。


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 {
            adapter = DetailAdapter()
            rv.adapter = adapter
            rv.itemAnimator = null

            // 添加组
            addSet.setOnClickListener {
                viewModel.addSet()
            }
            // 完成
            complete.setOnClickListener {
                findNavController().navigate(R.id.action_writeDetailFragment_to_addRoutineFragment)
            }
        }
        
        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 ->
                    adapter.submitList(list)
                }
            }
        }
    }
}

ViewModel代码

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

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

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

Repository代码

class WriteDetailRepository(val dao: WorkoutDao) {
    private var setInfoList = ArrayList<WorkoutSetInfo>()
    private lateinit var updatedList: List<WorkoutSetInfo>

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

问题根源与解决办法

问题根源

WriteDetailRepository是全局单例(从WorkoutApplication获取),其中的setInfoList是类成员变量,会在App生命周期内一直保留数据。每次新建Detail Fragment时,复用了同一个Repository实例,导致旧数据被保留。

解决办法

方案一:每次创建ViewModel时初始化新的Repository

修改ViewModelFactory,确保每次创建WriteDetailViewModel时生成新的WriteDetailRepository实例:

class WriteDetailViewModelFactory(
    private val dao: WorkoutDao // 从Application传入Dao,而非现成的Repository
) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(WriteDetailViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return WriteDetailViewModel(WriteDetailRepository(dao)) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

然后修改Fragment中获取ViewModel的代码:

private val viewModel: WriteDetailViewModel by viewModels {
    WriteDetailViewModelFactory(
        (requireActivity().application as WorkoutApplication).workoutDao
    )
}

方案二:给Repository添加重置方法

在Repository中添加清空列表的方法,在Fragment初始化时调用:

class WriteDetailRepository(val dao: WorkoutDao) {
    private var setInfoList = ArrayList<WorkoutSetInfo>()
    private lateinit var updatedList: List<WorkoutSetInfo>

    fun reset() {
        setInfoList.clear()
        updatedList = emptyList()
    }

    fun add() {
        val item = WorkoutSetInfo(set = setInfoList.size + 1)
        setInfoList.add(item)
        updatedList = setInfoList.toList()
    }

    fun getList() : List<WorkoutSetInfo> = updatedList
}

在ViewModel中新增对应方法:

fun resetSets() {
    viewModelScope.launch(Dispatchers.IO) {
        repository.reset()
        _items.value = repository.getList()
    }
}

最后在Fragment的onViewCreated中调用:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    viewModel.resetSets() // 初始化时清空数据
    // 其他原有代码...
}

额外优化建议

  • 避免在Repository中持有临时页面状态,这类状态应该由ViewModel管理,或者在页面销毁时主动清空。
  • 使用submitList时,确保每次传入新的List实例(比如通过toList()创建副本),保证Adapter能正确识别数据变化。

内容的提问来源于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 15:45:34