RecyclerView — DiffUtil

DiffUtil 16年出來(lái)的,是為了我餓們你在更新列表數(shù)據(jù)時(shí)可以實(shí)現(xiàn)動(dòng)畫(huà)效果

樣子是這樣的:


基礎(chǔ)部分我就不寫(xiě)了,大家看這里就行,寫(xiě)的挺清楚:

本文例子:

接下來(lái)我就來(lái)說(shuō)說(shuō)注意事項(xiàng)

1. DiffUtil 動(dòng)畫(huà)效果

DiffUtil 想出動(dòng)畫(huà)效果,必須給 RecyclerView 添加 item 動(dòng)畫(huà),item 動(dòng)畫(huà)的默認(rèn)是先類是 DefaultItemAnimator,并且 add,remove,update,move可以分貝設(shè)置時(shí)間

        var itemAnimator = DefaultItemAnimator()
        itemAnimator.addDuration = 3000
        itemAnimator.removeDuration = 3000
        itemAnimator.changeDuration = 3000
        itemAnimator.moveDuration = 3000

        recy_diff.itemAnimator = itemAnimator

默認(rèn)的 item 動(dòng)畫(huà)一般,推薦大家自己去做自己的效果

2. DiffUtil 動(dòng)畫(huà)的執(zhí)行順序

我這里為了明顯,每個(gè)動(dòng)畫(huà)是 3秒

DiffUtil 動(dòng)畫(huà)的執(zhí)行順序:

  • 先 remove
  • 再同時(shí) move 和 update
  • 最后 add

3. 4種動(dòng)畫(huà)對(duì)應(yīng)什么操作

我們只有知道自己的數(shù)據(jù)怎么變化,才能猜測(cè)出動(dòng)畫(huà)執(zhí)行的輪廓,然后調(diào)整不是

DiffUtil 對(duì)對(duì)比新舊2個(gè)集合對(duì)應(yīng) position 位置 item

  1. 先找新舊2個(gè)集合有沒(méi)有一樣的 item ,也就是 areContentsTheSame = true 的,然后計(jì)算位置,執(zhí)行 move 動(dòng)畫(huà)
  2. 在第一步的前提下,對(duì)比相同 position 位置是不是同一個(gè),也就是 item areItemsTheSame = false ,執(zhí)行 remove 動(dòng)畫(huà)
  3. 相同 position item ,areItemsTheSame = true,areContentsTheSame = false 的執(zhí)行 updata 動(dòng)畫(huà)
  4. 最后多出來(lái)位置的 item 執(zhí)行 add 動(dòng)畫(huà)

4. areItemsTheSame 方法意義

areItemsTheSame 需要特別注意,areItemsTheSame 書(shū)寫(xiě)不正當(dāng),非常容易觸發(fā)系統(tǒng) bug

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{431a7450 position=1 id=-1, oldPos=-1, pLpos:-1 scrap [attachedScrap] tmpDetached no parent}

這個(gè) bug 是系統(tǒng)拋出來(lái)的,無(wú)解,我們處理不了, 根本原因在于 areItemsTheSame 我們沒(méi)處理好

areItemsTheSame 方法的目的是:判斷新舊2個(gè)列表相同 positon 位置的 item 是否是同一個(gè),這個(gè)不光是判斷 item 是不是同一個(gè) itemtype,更要判斷這個(gè) item 的身份是不是同一個(gè),就好比時(shí)同一個(gè)人,比如這個(gè)人的衣服,前一分鐘是綠色的,然后變成了紅色,目的就是這樣,看是不是同一個(gè) item, 同一個(gè) item 有可能默寫(xiě)數(shù)據(jù)有變化,我們?cè)?areContentsTheSame 方法再去判斷數(shù)據(jù)是不是有變化,有變化更新數(shù)據(jù)

  • 若是同一個(gè)人,內(nèi)容也沒(méi)變化,那么這個(gè) item 就會(huì)做 move
  • 若是同一個(gè)人,但內(nèi)容有變化,那么在 areContentsTheSame 里面判斷并做內(nèi)容更新
  • 若不是同一個(gè)人,那么做 remove

我的例子是這樣寫(xiě)的:

        override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            if (!oldData.get(oldItemPosition).javaClass.equals(newData.get(newItemPosition).javaClass)) return false
            if (oldData.get(oldItemPosition) is Book && newData.get(newItemPosition) is Book) {
                var oldBook: Book = oldData.get(oldItemPosition) as Book
                var newBook: Book = newData.get(newItemPosition) as Book
                return oldBook.name.equals(newBook.name)
            }
            if (oldData.get(oldItemPosition) is Cat && newData.get(newItemPosition) is Cat) {
                var oldCat: Cat = oldData.get(oldItemPosition) as Cat
                var newCat: Cat = newData.get(newItemPosition) as Cat
                return oldCat.name.equals(newCat.name)
            }
            return false
        }

我的列表里有2種 itemtype ,之前只判斷了 itemtype 是不是一樣,結(jié)果頻繁報(bào) IndexOutOfBoundsException 這個(gè)異常,搞了半天想死的心都有,最后還是再次品鑒了翻 areItemsTheSame 方法的意義才 OK 的,大家這里碰到同樣的問(wèn)題,請(qǐng)不要著急,按我的思路求做,一準(zhǔn)沒(méi)問(wèn)題

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。