如何获取RecyclerView更新完成回调 避免列表新旧数据混杂展示
解决RecyclerView更新与数据源修改冲突的方案
核心前置规则
- 永远不要直接修改Adapter绑定的
ArrayList<User>实例,后台任务拿到新数据后先生成独立的数据集副本,再触发Adapter更新,从根源避免读写冲突。
方案1:使用AdapterDataObserver监听更新完成
这是官方提供的标准监听Adapter视图更新完成的方式,适配所有RecyclerView版本:
// 注册观察者 adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() { override fun onChanged() { super.onChanged() // 全局更新(notifyDataSetChanged)完成回调,此时可以执行下一次列表更新操作 executePendingUserListUpdate() } override fun onItemRangeInserted(positionStart: Int, itemCount: Int) { super.onItemRangeInserted(positionStart, itemCount) // 条目插入更新完成回调 executePendingUserListUpdate() } override fun onItemRangeChanged(positionStart: Int, itemCount: Int) { super.onItemRangeChanged(positionStart, itemCount) // 条目修改更新完成回调 executePendingUserListUpdate() } // 按需重写onItemRangeRemoved、onItemRangeMoved等其他回调即可 })
注意:不需要监听的时候要调用
unregisterAdapterDataObserver解绑,避免内存泄漏。
方案2:利用DiffUtil的完成回调(更推荐)
如果你用DiffUtil做增量更新,可以直接在提交更新的回调里拿到完成时机,性能比全局更新高很多:
// 后台线程计算Diff结果后,提交到Adapter val diffResult = DiffUtil.calculateDiff(UserDiffCallback(oldList, newCopyList)) diffResult.dispatchUpdatesTo(adapter) { // 此处回调即为增量更新完成时机 executePendingUserListUpdate() } // 同时把Adapter绑定的数据源替换为新的副本 adapter.userList = newCopyList
方案3:使用RecyclerView.post兜底
如果只是临时快速实现,可以给RecyclerView post任务,任务会在RecyclerView当前帧绘制完成后执行,此时视图更新已经结束:
adapter.notifyDataSetChanged(); recyclerView.post(() -> { // 视图更新完成,执行后续操作 executePendingUserListUpdate(); });
内容的提问来源于stack exchange,提问作者M.Toy
相关产品推荐
相关产品推荐

