RecyclerView-DiffUtil

1.前言

2.工具類要點(diǎn)

2.1 聲明并初始化AsyncListDiffer

private val mDiffer: AsyncListDiffer<T> 

2.2 創(chuàng)建DiffUtil.ItemCallback<T>,實(shí)現(xiàn)抽象方法

abstract fun areItemsTheSame(oldItem: T, newItem: T): Boolean
abstract fun areContentsTheSame(oldItem: T, newItem: T): Boolean

2.3 更新數(shù)據(jù)

fun setData(list: MutableList<T>?) {
    val newList: MutableList<T> = ArrayList()
    newList.addAll(list ?: ArrayList())
    mDiffer.submitList(newList) // 更新數(shù)據(jù)(setData()+notify())
}

3. 注意事項(xiàng)

3.1 不能重復(fù)提交同一個(gè)列表

  • 更新數(shù)據(jù)前(調(diào)用submitList(List<T> newList))盈蛮,請(qǐng)勿對(duì)"已被設(shè)置進(jìn)DiffUtil的list數(shù)據(jù)"進(jìn)行操作儡司。
  • 需重新創(chuàng)建list暇唾,以便DiffUtil進(jìn)行兩個(gè)新舊列表間對(duì)比。如舉例。

3.2 錯(cuò)誤示范

mData.add(...)
mAdapter.submitList(mData)

3.3 引發(fā)此問題原因

public class AsyncListDiffer<T> {
    // 更新數(shù)據(jù)
    public void submitList(@Nullable final List<T> newList, @Nullable final Runnable commitCallback) {
        // incrementing generation means any currently-running diffs are discarded when they finish
        final int runGeneration = ++mMaxScheduledGeneration;
        if (newList == mList) { // 此處進(jìn)行了過濾
            // nothing to do (Note - still had to inc generation, since may have ongoing work)
            if (commitCallback != null) {
                commitCallback.run();
            }
            return;
        }
        ...
    }
}

4. 基類封裝實(shí)現(xiàn)

使用DiffUtil進(jìn)行RecyclerView數(shù)據(jù)的對(duì)比&刷新澎嚣,把相關(guān)api進(jìn)行二次封裝击吱,以便為了更簡(jiǎn)單調(diào)用淋淀。

4.1 BaseRecyclerDifferItemCallBack

  • 對(duì)DiffUtil.ItemCallback<T>進(jìn)行二次封裝。
  • RecyclerView的dapter作為參數(shù)覆醇,把對(duì)比函數(shù)回調(diào)到Adapter進(jìn)行實(shí)現(xiàn)朵纷。
class BaseRecyclerDifferItemCallBack<T>(adapter: BaseRecyclerDifferAdapter<T>?) :
        DiffUtil.ItemCallback<T>() {

    private var mAdapter: BaseRecyclerDifferAdapter<T>? = adapter

    override fun areItemsTheSame(oldItem: T, newItem: T): Boolean {
        return mAdapter?.areItemsTheSame(oldItem, newItem)?: false
    }

    override fun areContentsTheSame(oldItem: T, newItem: T): Boolean {
        return mAdapter?.areContentsTheSame(oldItem, newItem)?: false
    }
}

4.2 BaseRecyclerDifferAdapter

  • 對(duì)RecyclerView.Adapter進(jìn)行二次封裝,初始化AsyncListDiffer變量用于數(shù)據(jù)操作永脓。
  • 創(chuàng)建數(shù)據(jù)對(duì)比抽象方法袍辞,用于此Adapter子類實(shí)現(xiàn)
abstract class BaseRecyclerDifferAdapter<T> : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private val mDiffer: AsyncListDiffer<T> by lazy {
        // 數(shù)據(jù)的操作由AsyncListDiffer實(shí)現(xiàn)
        AsyncListDiffer(this, BaseRecyclerDifferItemCallBack<T>(this))
    }

    fun getCurrentData(): MutableList<T> {
        return mDiffer.currentList
    }

    /**
     * 設(shè)置數(shù)據(jù)
     * @param list MutableList<T>?
     */
    fun setData(list: MutableList<T>?){
        val newList: MutableList<T> = ArrayList()
        newList.addAll(list?: ArrayList())
        mDiffer.submitList(newList)
    }


    /**
     * 添加數(shù)據(jù)
     * @param beans Array<out T>
     */
    fun addData(vararg beans: T) {
        val newList: MutableList<T> = ArrayList()
        newList.addAll(mDiffer.currentList)
        beans.forEach { bean ->
            newList.add(bean)
        }
        mDiffer.submitList(newList)
    }

    /**
     * 加載更多
     * @param list MutableList<T>?
     */
    fun loadMore(list: MutableList<T>?){
        val newList: MutableList<T> = ArrayList()
        newList.addAll(mDiffer.currentList)
        newList.addAll(list?: ArrayList())
        mDiffer.submitList(newList)
    }

    /**
     * 刪除數(shù)據(jù)
     * @param index Int
     */
    fun removeData(index: Int) {
        val newList: MutableList<T> = ArrayList()
        val currentList = mDiffer.currentList
        if (currentList.isNotEmpty() && index in 0 until currentList.size) {
            newList.addAll(currentList)
            newList.removeAt(index)
            mDiffer.submitList(newList)
        }
    }

    /**
     * 清空數(shù)據(jù)
     */
    fun clear() {
        mDiffer.submitList(null)
    }

    abstract fun areItemsTheSame(oldItem: T, newItem: T): Boolean
    abstract fun areContentsTheSame(oldItem: T, newItem: T): Boolean

4.2 業(yè)務(wù)Adapter實(shí)現(xiàn)

  • 舉例說明BaseRecyclerDifferAdapter使用方式
  • 以下為偽代碼,僅包含關(guān)鍵實(shí)現(xiàn)
class RVDifferAdapter(context: Context) : BaseRecyclerDifferAdapter<RVDifferBean>() {
    
    private var mContext: Context = context

    /**
     * Item對(duì)比
     */
    override fun areItemsTheSame(oldItem: RVDifferBean, newItem: RVDifferBean): Boolean {
        return oldItem.id == newItem.id // 比較邏輯自行實(shí)現(xiàn)
    }
    
    /**
     * Content對(duì)比
     */
    override fun areContentsTheSame(oldItem: RVDifferBean, newItem: RVDifferBean): Boolean {
        return oldItem.name == newItem.name // 比較邏輯自行實(shí)現(xiàn)
    }

    private var mInflater: LayoutInflater = LayoutInflater.from(context)

    /**
     * 獲取單條item數(shù)據(jù)
     *
     * @param position
     * @return
     */
    private fun getItemAtPosition(position: Int): RVDifferBean? {
        val itemCount: Int = itemCount
        return if (itemCount != 0 && position in 0 until itemCount) {
            getCurrentData()[position]
        } else {
            null
        }
    }

    override fun getItemCount(): Int {
        return getCurrentData().size
    }

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

    override fun onBindViewHolder(
        holder: RecyclerView.ViewHolder,
        position: Int,
        payloads: MutableList<Any>
    ) {
        super.onBindViewHolder(holder, position, payloads)
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    }
}

參考文檔:

官方文檔地址:[https://developer.android.google.cn/reference/kotlin/androidx/recyclerview/widget/DiffUtil]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末常摧,一起剝皮案震驚了整個(gè)濱河市革屠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌排宰,老刑警劉巖似芝,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異板甘,居然都是意外死亡党瓮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門盐类,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寞奸,“玉大人,你說我怎么就攤上這事在跳∏固眩” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵猫妙,是天一觀的道長瓷翻。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么齐帚? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任妒牙,我火速辦了婚禮,結(jié)果婚禮上对妄,老公的妹妹穿的比我還像新娘湘今。我一直安慰自己,他們只是感情好剪菱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布摩瞎。 她就那樣靜靜地躺著,像睡著了一般孝常。 火紅的嫁衣襯著肌膚如雪旗们。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天茫因,我揣著相機(jī)與錄音蚪拦,去河邊找鬼。 笑死冻押,一個(gè)胖子當(dāng)著我的面吹牛驰贷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洛巢,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼括袒,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了稿茉?” 一聲冷哼從身側(cè)響起锹锰,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎漓库,沒想到半個(gè)月后恃慧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渺蒿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年痢士,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茂装。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怠蹂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出少态,到底是詐尸還是另有隱情城侧,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布彼妻,位于F島的核電站嫌佑,受9級(jí)特大地震影響豆茫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜歧强,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一澜薄、第九天 我趴在偏房一處隱蔽的房頂上張望为肮。 院中可真熱鬧摊册,春花似錦、人聲如沸颊艳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棋枕。三九已至白修,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間重斑,已是汗流浹背兵睛。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窥浪,地道東北人祖很。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像漾脂,于是被迫代替她去往敵國和親假颇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容