RecyclerView刷新数据 - DiffUtil 的使用

DiffUtil 是一个实用程序类,用于计算两个列表之间的差异并输出将第一个列表转换为第二个列表,以有效更新 RecyclerView 显示的列表。

#1. notifyDataSetChanged

最常见的:

private var recyclerData: ArrayList<Any> = arrayListOf()
    
fun setData(data: List<Any>) {
    recyclerData.clear()
    recyclerData.addAll(data)
    notifyDataSetChanged()
}

⚠️  我们在为RecyclerView 列表刷新数据而使用 notifyDataSetChanged() 时,这个时候建议是在它最后一个数据资源加载完调用,即数据更新完最后调用刷新即可。

因为notifyDataSetChanged() 方法效率低,当 RecyclerView 列表中的某一项发生了变化需要更新时,此时调用 Adapter 中的 notifyDataSetChanged() ,notifyDataSetChanged() 会告诉 RecyclerView 整个列表可能无效。 结果RecyclerView 会重新绑定并重绘列表中的每个项目,包括在屏幕上不可见的项目。 这是很多不必要的工作。 对于大型或复杂的列表,此过程可能需要足够长的时间,以至于当用户滚动列表时显示会闪烁或断断续续。

为了解决这个问题,可以告诉 RecyclerView 到底发生了什么变化。 RecyclerView 然后只能更新屏幕上更改的视图。

RecyclerView 有一个丰富的 API 来更新单个元素。 您可以使用 notifyItemChanged() 告诉 RecyclerView 某个项目已更改,并且您可以对添加、删除或移动的项目使用类似的函数。 您可以手动完成所有操作,但该任务非常重要,并且可能涉及相当多的代码。

#2. DiffUtil

1- DiffUtil 高效并为您完成繁重的工作:
RecyclerView 有一个名为 DiffUtil 的类,用于计算两个列表之间的差异。 DiffUtil 使用旧列表和新列表并找出不同之处。 它查找添加、删除或更改的项目。 然后它使用一种称为 Eugene W. Myers 的差异算法的算法来计算从旧列表中进行的最小更改次数以生成新列表。

一旦 DiffUtil 找出发生了什么变化,RecyclerView 就可以使用该信息仅更新已更改、添加、删除或移动的项目,这比重做整个列表要高效得多。

2- 用DiffUtil刷新列表内容:

这会在 DiffUtil.Callback 内为两个方法生成存根: areItemsTheSame()areContentsTheSame() ,而 DiffUtil 就使用这两种方法来确定列表和项目是如何变化的。
 

#3.DiffUtil使用

这里在网上找到一个不错的封装使用:RecyclerViewDiffer.kt

interface RecyclerViewDiffer {

    fun <T> RecyclerView.Adapter<*>.notifyDataDispatchUpdate(old: List<T>, new: List<T>, compare: (T, T) -> Boolean) {
        val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() {

            override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                return compare(old[oldItemPosition], new[newItemPosition])
            }

            override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                return old[oldItemPosition] == new[newItemPosition]
            }

            override fun getOldListSize() = old.size

            override fun getNewListSize() = new.size
        })

        diff.dispatchUpdatesTo(this)
    }
}

封装用法:

// 使用 Diff Util 来刷新列表数据
var datas: List<String> by Delegates.observable(emptyList()) {
            property, oldValue, newValue ->
    notifyDataDispatchUpdate(oldValue, newValue) { old, new -> old == new }
}

 在适配器中示例:ThirdListAdapter.kt

class ThirdListAdapter : RecyclerView.Adapter<ThirdListViewHolder>(), RecyclerViewDiffer {

    // 使用 Diff Util 来刷新列表数据
    var datas: List<String> by Delegates.observable(emptyList()) {
            property, oldValue, newValue ->
        notifyDataDispatchUpdate(oldValue, newValue) { old, new -> old == new }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ThirdListViewHolder {
        return ThirdListViewHolder(parent.viewBinding(ItemThirdBinding::inflate))
    }

    override fun getItemCount(): Int {
        return datas.size
    }

    override fun onBindViewHolder(holder: ThirdListViewHolder, position: Int) {
        holder.bindData(datas[position])
    }
}

具体的项目地址中可查看 RecyclerViewDiffer.ktMVVM-Project-Hilt

(欢迎讨论) 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值