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

Android Room+LiveData更新数据后如何恢复RecyclerView滚动位置

问题根因与解决方案

1. 滚动位置自动回到顶部的原因

你最初的代码每次收到LiveData回调都会重新创建TasksListAdapter实例,再给RecyclerView重新设置adapter,相当于完全重置列表状态,所以会自动滚动到顶部,同时还会全量重绘所有item,性能也较差。你后续优化复用Adapter的逻辑已经解决了这个问题。

2. 首次打开偶尔列表为空的原因

你更新了Adapter内部的taskList数据集后,没有调用RecyclerView.Adapter的数据集变更通知方法,RecyclerView不知道数据已经更新,就不会触发列表重绘,因此会一直显示初始的空列表,直到下次主动刷新。


修正方案

方案1:使用DiffUtil差分刷新(推荐,性能最优)

仅需修改Adapter的taskList setter逻辑,自动计算数据变化、只刷新改动的条目,不会触发整体滚动,性能远高于全量刷新:

private inner class TasksListAdapter(): RecyclerView.Adapter<TaskHolder>(){
    var taskList: List<TasksItemHolder> = emptyList()
        set(value){
            val diffResult = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
                override fun getOldListSize() = field.size
                override fun getNewListSize() = value.size
                // 用唯一ID判断是否为同一个条目
                override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                    return field[oldItemPosition].id == value[newItemPosition].id
                }
                // 判断条目内容是否发生变化
                override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                    return field[oldItemPosition] == value[newItemPosition]
                }
            })
            field = value
            diffResult.dispatchUpdatesTo(this)
        }

    // 原有逻辑保持不变
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TaskHolder {
        val view = layoutInflater.inflate(R.layout.tasks_list_item, parent, false)
        return TaskHolder(view)
    }

    override fun onBindViewHolder(holder: TaskHolder, position: Int) {
        holder.bind(taskList[position])
    }

    override fun getItemCount() = taskList.size
}

方案2:全量刷新(适合小数据量列表,实现简单)

如果你的列表数据量很小,也可以直接在数据集更新后调用全量通知:

private inner class TasksListAdapter(): RecyclerView.Adapter<TaskHolder>(){
    var taskList: List<TasksItemHolder> = mutableListOf()
        set(value){
            field = value
            notifyDataSetChanged()
        }
    // 剩余逻辑保持不变
}

冗余逻辑清理

可以删除onCreate里的Adapter初始赋值逻辑,避免重复赋值,LiveData返回数据后会自动更新列表:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    taskAdapter = TasksListAdapter()
    date = arguments?.getString(DATE_KEY) as String
    taskListViewModel.loadDate(date)
}

修改完成后,两个问题都会解决:点击CheckBox仅会刷新对应条目,滚动位置不会变动,首次进入应用也不会出现列表空白的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 20:00:03