Android

DiffUtil 优雅替代RecyclerView 刷新(一)

2021-09-07  本文已影响0人  没有了遇见

DiffUtil 用于计算两个列表之间的差异并输出将第一个列表转换为第二个列表的更新操作列表,它可用于计算 RecyclerView 适配器的更新.

官方简介语法

Diffutil处理数据耗时

出现原先:

DiffUtil 同步方案处理大量数据的时候耗时较长衍生出异步方案

解决方案:

AsyncListDiffer 在后台通过 DiffUtil 计算两个列表之间的差异的助手

主要方案:

同步方案:主要方法 DiffUtil.calculateDiff() ,DiffUtil.Callback(),DiffResult.dispatchUpdatesTo()

Adapter代码(主要参考onBindViewHolder)

class MainAdapter(mContext: Context) : KtAdapter<UserInfo>(mContext) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {

    var binding = DataBindingUtil.inflate<ItemMainOneBinding>(
        LayoutInflater.from(mContext),
        R.layout.item_main_one,
        parent,
        false
    )
    var holder = KtDataBindingViewHolder(binding.root)
    holder.binding = binding
    return holder

}

/**
 * @param payloads A non-null list of merged payloads. Can be empty list if requires full
 *                update.
 */

override fun onBindViewHolder(
    holder: RecyclerView.ViewHolder,
    position: Int,
    payloads: MutableList<Any>
) {
    // payloads  为null 整条数据刷新
    if (payloads.isEmpty() || payloads.size <= 0) {
        super.onBindViewHolder(holder, position, payloads)
    } else {
        //局部更新   不会更新整个item 更新指定的控件
        var bundle = payloads.get(0) as Bundle
        if (bundle != null) {
            var name = bundle.getString("name")
            var phoneNum = bundle.getString("phoneNum")
            var holder = holder as KtDataBindingViewHolder
            var binding = holder.binding as ItemMainOneBinding
            if (!TextUtils.isEmpty(name)) {
                binding.tvName.text = name
            }
            if (!TextUtils.isEmpty(phoneNum)) {
                binding.tvPhone.text = phoneNum
            }
        }
    }


}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    Log.e("绘制:", "" + position)
    var holder = holder as KtDataBindingViewHolder
    var binding = holder.binding as ItemMainOneBinding
    binding.tvName.setText(getItem(position)!!.name)
    binding.tvPhone.setText(getItem(position)!!.phoneNum)
}

}

方法介绍:

1:DiffUtil:主要方法工具类
2:DiffUtil.calculateDiff(callback,list),计算可以将一个列表转换为另一个列表的更新操作列表。
3:Callback :计算两个不通集合的回调 (自己实现这个类处理,两个数据合并成一个数据)

A:getNewListSize() 新数据集合个数

B:getOldListSize() 旧数据的个数 

C:areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): 根据某个属性判断是否是一个数据(某唯一值判断,一般是ID)

D:areContentsTheSame(oldItemPosition: Int, newItemPosition: Int):同一个数据参数属性是否相同(对象的属性)

E:getChangePayload(oldItemPosition: Int, newItemPosition: Int) :属性变动执行此方法(单条数据局部刷新需要执行)

代码:

import android.os.Bundle
import android.text.TextUtils
import androidx.recyclerview.widget.DiffUtil


/**
 * @author wkq
 *
 * @date 2021年09月06日 14:33
 *
 *@des
 *
 */

class RecyclerViewDiffCallBack(oldList: List<UserInfo>, newList: List<UserInfo>) : DiffUtil.Callback() {
    var oldList: List<UserInfo>? = null
    var newList: List<UserInfo>? = null

    init {
        this.oldList = oldList
        this.newList = newList
    }

    //旧数据集的长度;
    override fun getOldListSize(): Int {
       if (oldList.isNullOrEmpty()) {
            return 0
        } else {
            return oldList!!.size
        }
    }

    //获取新数据长度
    override fun getNewListSize(): Int {
        if (newList.isNullOrEmpty()) {
            return 0
        } else {
            return newList!!.size
        }
    }

    //判断是否是同一个item  为true 进入areContentsTheSame
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        if (oldList == null || oldList == null) return false
        var oldItemId = oldList!![oldItemPosition].id
        var newItemId = newList!![newItemPosition].id
        return oldItemId!!.equals(newItemId)

    }

    // 如果item相同,此方法用于判断是否同一个 Item 的内容也相同  为false进入 getChangePayload
    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        if (oldList == null || oldList == null) return false
        var oldItem = oldList!![oldItemPosition].toString()
        var newItem = newList!![newItemPosition].toString()
        return oldItem.equals(newItem)
    }

    //  局部刷新  返回null 整条数据刷新
    override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
        var oldItem = oldList!![oldItemPosition]
       var newItem = newList!![newItemPosition]

        var bundle=Bundle()
           // onBindViewHolder  实现三个参数  payloads   第一个数据为  封装的bundle
        if (!TextUtils.equals(oldItem.name,newItem.name)){
            bundle.putString("name",newItem.name)
        }
        if (!TextUtils.equals(oldItem.icon,newItem.icon)){
            bundle.putString("icon",newItem.name)
        }
        if (!TextUtils.equals(oldItem.phoneNum,newItem.phoneNum)){
            bundle.putString("phoneNum",newItem.phoneNum)
        }
        return bundle
    }

}

4: DiffResult :DiffUtil.calculateDiff()获取差分数据的结果

5:DiffResult.dispatchUpdatesTo(adapter):将更新事件分派给给定的适配器。

代码:

  private fun setNewData() {
    var userList = ArrayList<UserInfo>()
    for (index in 0..mAdapter!!.getItems()!!.size) {
        var userInfo = UserInfo()
        if (index == 0) {
            userInfo.name = "开始"
        } else if (index == mAdapter!!.getItems()!!.size) {
            userInfo.name = "结束"
        } else {
            userInfo.name = "测试" + index
        }
        userInfo.id = index
        userInfo.phoneNum = "1853853738" + index
        userList.add(userInfo)
    }
    var result = DiffUtil.calculateDiff(RecyclerViewDiffCallBack(mAdapter!!.getItems()!!, userList))

    mAdapter!!.setDatas(userList)

    result.dispatchUpdatesTo(mAdapter!!)
}

总结

1.源码下载,欢迎Star

2.DiffUtil 优雅替代RecyclerView 刷新(二)AsyncListDiffer 异步刷新

上一篇下一篇

猜你喜欢

热点阅读