前言
自Android5.0以来,RecyclerView渐渐取代ListView成为Android开发中使用最多的列表控件,对于RecyclerView的使用相信大家都不陌生,但对于RecyclerView的高效刷新,却是很多人不知道的。
简单粗暴的刷新方式
Adapter.notifyDataSetChanged()
这种方式想必是大家曾经用的最多的一种刷新Adapter的方式,它的缺点很明显:
- 无脑刷新整个RecyclerView可视区域,每个item重绘,如果你的onBindViewHolder逻辑处理稍微复杂一些,则容易造成卡顿
- 无法触发RecyclerView的item动画,用户体验极差。
局部刷新方式
为了解决上述问题,RecyclerView推出了局部刷新的方式
Adapter.notifyItemChanged(int)
Adapter.notifyItemInserted(int)
Adapter.notifyItemRangeChanged(int, int)
Adapter.notifyItemRangeInserted(int, int)
Adapter.notifyItemRangeRemoved(int, int)
局部刷新只会刷新指定position的item,这样完美解决了上述简单粗暴刷新方式的缺点,局部刷新需要指定item的position,如果你只更新了一条数据,那么你可以很容易知道position位置,但是如果你更新的是整个列表,你需要计算出所有你需要刷新的position,那么这将是一场灾难。
DiffUtil
Google似乎也注意到了这一点,因此在support-recyclerview-v7:24.2.0
中,推出了一个用于计算哪些位置需要刷新的工具类:DiffUtil。
使用DiffUtil,有3个步骤:
1.自实现DiffUtil.callback
class MyDiffUtilCallback(private val mOldList: List<User>, private val mNewList: List<User>) : DiffUtil.Callback() {
override fun getOldListSize(): Int {
// 返回旧数据的长度
return mOldList.size
}
override fun getNewListSize(): Int {
// 返回新数据的长度
return mNewList.size
}
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
// 返回两个item是否相同
// 例如:此处两个item的数据实体是User类,所以以id作为两个item是否相同的依据
// 即此处返回两个user的id是否相同
return mOldList[oldItemPosition].id