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