自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

RecyclerView配合DiffUtil,好用到飛

開發(fā) 開發(fā)工具
DIffUtils 是 Support-v7:24:2.0 中,更新的工具類。因為已經(jīng)更新了一段時間了,也不好說是最新更新的。

 [[200515]]

一、前言

DIffUtils 是 Support-v7:24:2.0 中,更新的工具類。因為已經(jīng)更新了一段時間了,也不好說是***更新的。

它主要是為了配合 RecyclerView 使用,通過比對新、舊兩個數(shù)據(jù)集的差異,生成舊數(shù)據(jù)到新數(shù)據(jù)的最小變動,然后對有變動的數(shù)據(jù)項,進行局部刷新。

接下來就 DiffUtil 的使用細節(jié),進行一個詳細的講解,希望一篇文章就完全理解 DiffUtil。

二、為什么會有DiffUtil

RecyclerView 自從被發(fā)布以來,一直被說成是 ListView、GridView 等一系列列表控件的***替代品。并且它本身使用起來也非常的好用,布局切換方便、自帶 ViewHolder 、局部更新并且可帶更新動畫等等。

局部更新、并且可以很方便的設置更新動畫這一點,是 RecyclerView 一個不錯的亮點。它為此提供了對應的方法:

  • adapter.notifyItemChange()
  • adapter.notifyItemInserted()
  • adapter.notifyItemRemoved()
  • adapter.notifyItemMoved()

以上方法都是為了對數(shù)據(jù)集中,單一項進行操作,并且為了操作連續(xù)的數(shù)據(jù)集的變動,還提供了對應的 notifyRangeXxx() 方法。

雖然 RecyclerView 提供的局部更新的方法,看似非常的好用,但是實際上,其實并沒有什么用。

在實際開發(fā)中,最方便的做法就是無腦調(diào)用 notifyDataSetChanged(),用于更新 Adapter 的數(shù)據(jù)集。

雖然 notifyDataSetChanged() 有一些缺點:

  • 不會觸發(fā) RecyclerView 的局部更新的動畫。
  • 性能低,會刷新整個 RecyclerView 可視區(qū)域。

但是真有需要頻繁刷新,前后兩個數(shù)據(jù)集的場景。

方案一:使用一個 notifyDataSetChanged() 方法。

方案二:自己寫一個數(shù)據(jù)集比對方法,然后去計算他們的差值,***調(diào)用對應的方法更新到 RecyclerView 中去。

我這么懶,如果不是必要,當然是會選 方案一 了。畢竟和之前 ListView 的時候,也沒有更差了。

Google 顯然也發(fā)現(xiàn)了這個問題,所以 DiffUtil 被發(fā)布了。

三、介紹DiffUtil

就像前面說的,DiffUtil 就是為了解決這個痛點的。它能很方便的對兩個數(shù)據(jù)集之間進行比對,然后計算出變動情況,配合 RecyclerView.Adapter ,可以自動根據(jù)變動情況,調(diào)用 Adapter 的對應方法。

當然,DiffUtil 不僅只能配合 RecyclerView 使用,它實際上可以單獨用于比對兩個數(shù)據(jù)集,然后如何操作是可以定制的,那么在什么場景下使用,就全憑我們自己發(fā)揮了。

DiffUtil 在使用起來,主要需要關注幾個類:

  • DiffUtil.Callback:具體用于限定數(shù)據(jù)集比對規(guī)則。
  • DiffUtil.DiffResult:比對數(shù)據(jù)集之后,返回的差異結果。

1、DiffUtil.Callback

DiffUtil.Callback 主要就是為了限定兩個數(shù)據(jù)集中,子項的比對規(guī)則。畢竟開發(fā)者面對的數(shù)據(jù)結構多種多樣,既然沒法做一套通用的內(nèi)容比對方式,那么就將比對的規(guī)則,交還給開發(fā)者來實現(xiàn)即可。

在 Callback 中,其實只需要實現(xiàn) 4 個方法:

  • getOldListSize():舊數(shù)據(jù)集的長度。
  • getNewListSize():新數(shù)據(jù)集的長度
  • areItemsTheSame():判斷是否是同一個Item。
  • areContentsTheSame():如果是通一個Item,此方法用于判斷是否同一個 Item 的內(nèi)容也相同。

前兩個是獲取數(shù)據(jù)集長度的方法,這沒什么好說的。但是后兩個方法,主要是為了對應多布局的情況產(chǎn)生的,也就是存在多個 viewType 和多個 ViewHodler 的情況。首先需要使用 areItemsTheSame() 方法比對是否來自同一個 viewType(也就是同一個 ViewHolder ) ,然后再通過 areContentsTheSame() 方法比對其內(nèi)容是否也相等。

其實 Callback 還有一個 getChangePayload() 的方法,它可以在 ViewType 相同,但是內(nèi)容不相同的時候,用 payLoad 記錄需要在這個 ViewHolder 中,具體需要更新的View。

areItemsTheSame()、areContentsTheSame()、getChangePayload() 分別代表了不同量級的刷新。

首先會通過 areItemsTheSame() 判斷當前 position 下,ViewType 是否一致,如果不一致就表明當前 position 下,從數(shù)據(jù)到 UI 結構上全部變化了,那么就不關心內(nèi)容,直接更新就好了。如果一致的話,那么其實 View 是可以復用的,就還需要再通過 areContentsTheSame() 方法判斷其內(nèi)容是否一致,如果一致,則表示是同一條數(shù)據(jù),不需要做額外的操作。但是一旦不一致,則還會調(diào)用 getChangePayload() 來標記到底是哪個地方的不一樣,最終標記需要更新的地方,最終返回給 DiffResult 。

當然,對性能要是要求沒那么高的情況下,是可以不使用 getChangedPayload() 方法的。

2、DiffUtil.DiffResult

DiffUtil.DiffResult 其實就是 DiffUtil 通過 DiffUtil.Callback 計算出來,兩個數(shù)據(jù)集的差異。它是可以直接使用在 RecyclerView 上的。如果有必要,也是可以通過實現(xiàn) ListUpdateCallback 接口,來比對這些差異的。

3、使用DiffUtil

介紹了 Callback 和 DiffResult 之后,其實就可以正常使用 DiffUtil 來進行數(shù)據(jù)集的比對了。

在這個過程中,其實真的很簡單,只需要調(diào)用兩個方法:

  1. DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallBack(oldDatas, newDatas), true);  
  2. diffResult.dispatchUpdatesTo(mAdapter); 

calculateDiff 方法主要是用于通過一個具體的 DiffUtils.Callback 實現(xiàn)對象,來計算出兩個數(shù)據(jù)集差異的結果,得到 DiffUtil.DiffResult 。

而 calculateDiff 的另外一個參數(shù),用于標記是否需要檢測 Item 的移動。

DiffUtil 使用的是 Eugene Myers 的差別算法,這個算法本身是不檢查元素的移動的。也就是說,有元素的移動它也只是會先標記為刪除,然后再標記插入。而如果需要計算元素的移動,它實際上也是在通過 Eugene Myers 算法比對之后,再進行一次移動檢查。所以,如果集合本身已經(jīng)排序過了,可以不進行移動的檢查。

而 dispatchUpdatesTo() 就是將這個數(shù)據(jù)集差異的結果,通過 Adapter 更新到 RecyclerView 上面。

實際上 dispatchUpdatesTo(Adapter) ,也是使用的 ListUpdateCallback 這個接口,在其中獲得差異,然后調(diào)用 Adapter 的對應方法。

四、上例子

既然已經(jīng)說清楚了,那么我們開始上例子了。

功能很簡單,有四個數(shù)據(jù)集,使用 RecyclerView 承載,然后有一個按鈕,用于輪換的切換數(shù)據(jù)集。

1、實現(xiàn) DiffUtil.Callback

為了簡單,RecyclerView 中使用單一 ViewType ,并且使用一個 TextView 承載一個 字符串來顯示。

那么我們開始實現(xiàn) Callback:

 

2、切換數(shù)據(jù)集

既然已經(jīng)有了 DiffUtil.Callback 的實現(xiàn)之后,我們就需要對切換數(shù)據(jù)集的點擊事件進行處理了。

3、實現(xiàn)效果

關鍵代碼已經(jīng)貼出來了,其實非常的簡單,最終運行的效果如下:

五、DiffUtil 效率問題

既然 DiffUtil 非常的好用,并且內(nèi)部也實現(xiàn)了一套算法,但是我們也需要關心它的效率問題。

根據(jù) Google 官方文檔中給出的例子,在 Nexus 5X M 系統(tǒng)上,DiffUtil 的效率問題,給出了一些參考的數(shù)據(jù):

可以看到,實際上,DiffUtil 的算法把效率問題解決的非常的好。在開啟計算移動的情況下,1000 條數(shù)據(jù)中有 200 個修改,平均值也只有 13.54 ms ,基本上都是毫秒級的。

Google 官方同時也指出,如果是對大數(shù)據(jù)集的比對,***是方在子線程中去完成計算,也就是其實是存在堵塞 UI 的情況的。所以如果你遇見了使用 DiffUtil 之后,每次刷新有卡頓的情況,可以考慮是否數(shù)據(jù)集太大,是否應該在子線程中完成計算。

六、結語

DiffUtil 已經(jīng)介紹完了,如果覺得本文對你有幫助。都看到這里了,點個贊再走吧。

 

【本文為51CTO專欄作者“張旸”的原創(chuàng)稿件,轉載請通過微信公眾號聯(lián)系作者獲取授權】

戳這里,看該作者更多好文

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2025-04-18 08:24:22

2021-07-19 15:47:45

Python編程語言代碼

2020-08-23 09:30:32

jupyter lab插件開發(fā)

2022-04-12 08:43:21

Python內(nèi)置模塊

2018-07-10 09:36:25

2020-09-20 22:04:11

Windows 工具系統(tǒng)

2021-10-06 15:58:26

Python工具代碼

2012-08-10 10:10:05

視頻會議飛視美

2023-12-12 13:49:00

差量算法Myers

2021-11-15 10:02:16

Python命令技巧

2023-04-26 00:34:36

Python技巧程序員

2022-03-29 18:18:07

Kubernetes框架

2022-02-24 10:48:01

Pycharm插件

2024-07-19 10:31:15

2022-07-17 11:45:39

微服務架構

2022-01-13 11:50:57

Python技巧代碼

2020-10-14 18:53:14

Python編程語言

2021-04-12 11:05:09

Windows微軟軟件

2021-11-26 10:36:36

瀏覽器插件谷歌

2023-07-03 08:29:01

點贊
收藏

51CTO技術棧公眾號