recyclerview優化 DiffUtils 局部刷新

DiffUtils 是Support-v7:24:2.0中,更新的工具類。app

DiffUtil是一個實用程序類,能夠計算兩個列表之間的差別,並輸出將第一個列表轉換爲第二個列表的更新操做列表。ide

它主要是爲了配合 RecyclerView 使用,經過比對新、舊兩個數據集的差別,生成舊數據到新數據的最小變更,而後對有變更的數據項,進行局部刷新。工具

class ComicDiffCallBack(private val mOldDataList: ArrayList<ComicBean>?, private val mNewDataList: ArrayList<ComicBean>?) : DiffUtil.Callback() {

    //兩個對象是不是相同的Item,例如,若是你的Item有惟一的id字段,這個方法就 判斷id是否相等。
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        if (mOldDataList != null && mNewDataList != null) {
            val oldData = mOldDataList[oldItemPosition]
            val newData = mNewDataList[newItemPosition]
            if (oldData.id == newData.id) {
                return true
            }
            if (TextUtils.equals(oldData.title, newData.title)) {
                return true
            }
        }
        return false
    }

    override fun getOldListSize(): Int = mOldDataList?.size ?: 0

    override fun getNewListSize(): Int = mNewDataList?.size ?: 0

    //用來檢查 兩個item是否含有相同的數據
    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        if (mOldDataList != null && mNewDataList != null) {
            val oldData = mOldDataList[oldItemPosition]
            val newData = mNewDataList[newItemPosition]
            when {
                oldData.type != newData.type -> return false
                !TextUtils.equals(oldData.title, newData.title) -> return false
                !TextUtils.equals(oldData.cover, newData.cover) -> return false
                !TextUtils.equals(oldData.describe, newData.describe) -> return false
            }
        }
        return true
    }

    override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
        if (mOldDataList == null || mNewDataList == null) {
            return null
        }
        val oldData = mOldDataList[oldItemPosition]
        val newData = mNewDataList[newItemPosition]
        val payload = Bundle()
        if (!TextUtils.equals(oldData.title, newData.title)) {
            payload.putString(KeyConst.MainComic.TITLE, newData.title)
        }
        if (!TextUtils.equals(oldData.cover, newData.cover)) {
            payload.putString(KeyConst.MainComic.COVER, newData.cover)
        }
        if (!TextUtils.equals(oldData.describe, newData.describe)) {
            payload.putString(KeyConst.MainComic.DESC, newData.describe)
        }
        if (payload.size() == 0) {
            return null
        }
        return payload
   }
}


data class ComicBean(var title:String,var cover: String,var describe:String)

object KeyConst {
    object MainComic {
       const val TITLE = "KEY_COMIC_TITLE"
       const val COVER = "KEY_COMIC_COVER"
       const val DESC = "KEY_COMIC_DESC"
   }
}
複製代碼

DiffUtil能夠獲得一個變動集合DiffResult,DiffResult會根據數據的增刪改去調用Adapter的notifyItemRangeInserted、notifyItemRangeRemoved、notifyItemMoved、notifyItemRangeChangedspa

Adaptercode

override fun onBindViewHolder(holder: ViewHolder?, position: Int, payloads: List<Any>?) {
    ComicBean t = mList[position]
    if (payloads != null) {
        val payload = payloads[0] as Bundle
        for (key in payload.keySet()) {
            when (key) {
                KeyConst.MainComic.TITLE -> holder?.setText(R.id.iv_img_small_title, t?.title)
                KeyConst.MainComic.COVER -> holder?.setImageLoad(R.id.iv_img_small_cover, t?.cover)
                KeyConst.MainComic.DESC -> {
                    holder?.setImageLoad(R.id.iv_img_small_cover, t?.cover)
                    holder?.getView<TextView>(R.id.iv_img_small_desc)?.apply {
                        visibility = View.VISIBLE
                        text = t?.describe
                    }
                }
            }
        }
    } else {
        holder?.setText(R.id.iv_img_small_title, t?.title)
        holder?.setImageLoad(R.id.iv_img_small_cover, t?.cover)
        holder?.getView<TextView>(R.id.iv_img_small_desc)?.apply {
            visibility = View.VISIBLE
            text = t?.describe
        }
    }
}
複製代碼

使用對象

DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new ItemDiffCallBack(mList, mNewList));
diffResult.dispatchUpdatesTo(mAdapter);
複製代碼

局部刷新子Viewget

若是使用 notifyItemChanged(int position, @Nullable Object payload) 方法,則會回調it

onBindViewHolder(@NonNull VH holder, int position,@NonNull List payloads) 方法。io

注意 若是有HeaderView Position沒有算頭部有問題class

相關文章
相關標籤/搜索