1. 程式人生 > >RecyclerView配合DiffUtil,資料對比,區域性重新整理

RecyclerView配合DiffUtil,資料對比,區域性重新整理

本文轉載自作者: 承香墨影,附上作者微信和公眾號

作者微信和公眾號

一、前言

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

它主要是為了配合RecyclerView 使用,通過比對新、舊兩個資料集的差異,生成舊資料到新資料的最小變動,然後對有變動的資料項,進行區域性重新整理。

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

二、為什麼會有DiffUtil

RecyclerView 自從被髮布以來,一直被說成是 ListView、GridView 等一系列列表控制元件的完美替代品。並且它本身使用起來也非常的好用,佈局切換方便、自帶ViewHolder、區域性更新並且可帶更新動畫等等。

區域性更新、並且可以很方便的設定更新動畫這一點,是 RecyclerView 一個不錯的亮點。它為此提供了對應的方法:

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

以上方法都是為了對資料集中,單一項進行操作,並且為了操作連續的資料集的變動,還提供了對應的 notifyRangeXxx() 方法。

雖然 RecyclerView 提供的區域性更新的方法,看似非常的好用,但是實際上,其實並沒有什麼用。

在實際開發中,最方便的做法就是無腦呼叫 notifyDataSetChanged(),用於更新 adapter 的資料集。

雖然 notifyDataSetChanged 有一些缺點:

不會觸發 RecyclerView 的區域性更新的動畫。
效能低,會重新整理整個 RecyclerView 可視區域。

但是真有需要頻繁重新整理,前後兩個資料集的場景,一個 notifyDataSetChanged() 方法,會比自己寫一個數據集比對方法,然後去計算他們的差值,最後呼叫對應的方法更新到 RecyclerView 中去。

我這麼懶,如果不是必要,當然是會選 notifyDataSetChanged() 了。畢竟和之前 ListView 的時候,也沒有更差了。

Google 顯然也發現了這個問題,所以 DiffUtil 被髮布了。

三、介紹DiffUtil

就像前面說的,DiffUtil 就是為了解決這個痛點的。它能很方便的對兩個資料集之間進行比對,然後計算出變動情況,配合RecyclerView.Adapter ,可以自動根據變動情況,呼叫 adapter 的對應方法。

當然,DiffUtil 不僅只能配合 RecyclerView 使用,它實際上可以單獨用於比對兩個資料集,然後如何操作是可以定製的,那麼在什麼場景下使用,就全憑我們自己發揮了。

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

DiffUtil.Callback:具體用於限定資料集比對規則。
DiffUtil.DiffResult:比對資料集之後,返回的差異結果。

1、DiffUtil.Callback

DiffUtil.Callback 主要就是為了限定兩個資料集中,子項的比對規則。畢竟開發者面對的資料結構多種多樣,既然沒法做一套通用的內容比對方式,那麼就將比對的規則,交還給開發者來實現即可。

在 Callback 中,其實只需要實現 4 個方法:

getOldListSize():舊資料集的長度。
getNewListSize():新資料集的長度
areItemsTheSame():判斷是否是同一個Item。
areContentsTheSame():如果是通一個Item,此方法用於判斷是否同一個 Item 的內容也相同。

前兩個是獲取資料集長度的方法,這沒什麼好說的。但是後兩個方法,主要是為了對應多佈局的情況產生的,也就是存在多個 viewType 和多個 ViewHodler 的情況。首先需要使用 areItemsTheSame() 方法比對是否是同一個 viewType(也就是同一個ViewHolder) ,然後再通過 areContentsTheSame() 方法比對其內容是否也相等。

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

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

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

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

2、DiffUtil.DiffResult

DiffUtil.DiffResult 其實就是 DiffUtil 通過 DiffUtil.Callback 計算出來,兩個資料集的差異。它是可以直接使用在 RecyclerView 上的。如果有必要,也是可以通過實現 ListUpdateCallback 介面,來比對這些差異的。

3、使用DiffUtil

介紹了 Callback 和 DiffResult 之後,其實就可以正常使用 DiffUtil 來進行資料集的比對了。

在這個過程中,其實其實很簡單,只需要呼叫兩個方法:

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

calculateDiff 方法主要是用於通過一個具體的 DiffUtils.Callback 實現物件,來計算出兩個資料集差異的結果,得到 DiffUtil.DiffResult 。

而 calculateDiff 的另外一個引數,用於標記是否需要檢測 Item 的移動。

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

而 dispatchUpdatesTo() 就是將這個資料集差異的結果,通過 adapter 更新到 RecyclerView 上面。

實際上 dispatchUpdatesTo(Adapter) ,也是使用的ListUpdateCallback 這個介面,在其中獲得差異,然後呼叫 adapter 的對應方法。

這裡寫圖片描述

四、上例子

既然已經說清楚了,那麼我們開始上例子了。

功能很簡單,有四個資料集,使用 RecyclerView 承載,然後有一個按鈕,用於輪換的切換資料集。

1、實現 DiffUtil.Callback

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

那麼我們開始實現 Callback:

這裡寫圖片描述

2、切換資料集

既然已經有了 DiffUtil.Callback 的實現之後,我們就需要對切換資料集的點選事件進行處理了。

這裡寫圖片描述

3、實現效果

關鍵程式碼已經貼出來了,其實非常的簡單,最終執行的效果如下:

這裡寫圖片描述

五、DiffUtil 效率問題

既然DiffUtil 非常的好用,並且內部也實現了一套演算法,但是我們也需要關心它的效率問題。

根據 Google 官方文件中給出的例子,在 Nexus 5X M 系統上,DiffUtil 的效率問題,給出了一些參考的資料:
這裡寫圖片描述

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

Google 官方同時也指出,如果是對大資料集的比對,最好是方在子執行緒中去完成計算,也就是其實是存在堵塞 UI 的情況的。所以如果你遇見了使用 DiffUtil 之後,每次重新整理有卡頓的情況,可以考慮是否資料集太大,是否應該在子執行緒中完成計算。

相關推薦

RecyclerView配合DiffUtil資料對比區域性重新整理

本文轉載自作者: 承香墨影,附上作者微信和公眾號 一、前言 DIffUtils 是 Support-v7:24:2.0 中,更新的工具類。因為已經更新了一段時間了,也不好說是最新更新的。 它主要是為了配合RecyclerView 使用,通過比對新、舊兩

RecyclerView配合DiffUtil區域性重新整理完整例子

廢話不多說,上來就先看效果吧。點選“模擬重新整理”按鈕完成第二、三項列表中的描述文字和下面的滾動動畫的重新整理。第二次進入直接下拉到列表底部點選“模擬重新整理”按鈕,同樣可以完成定向重新整理。這應該是我們期待的效果吧。這樣的功效就是普通的RecyclerView配合DiffU

(石頭、剪刀、布)shell腳本隨機對比case的應用

評論 單獨 三種 數組 石頭 兩種方法 == dom ash 腳本實現人機<石頭,剪刀,布>遊戲,機器應用隨機方法,結合用戶輸入給出結果,文章有兩種方法,重在理解,第一種方法是該腳本的邏輯方面,第二種較容易理解。一 : 第一種方法,讓機器給出一個隨機數字 0-2

MySQL—概念使用者的建立主鍵外來鍵資料型別表格建立

MySQL   DBMS,MySQL的概念,資料庫分類,以前MySQL的部署中的一些概念 #DBMS:資料庫管理系統,用於管理資料庫的大型軟體。mysql就是dbms的一種 #Mysql:是用於管理檔案的一個軟體 #服務端軟體

38套大資料雲端計算架構資料分析師HadoopSparkStormKafka人工智慧機器學習深度學習專案實戰視訊教程

38套大資料,雲端計算,架構,資料分析師,Hadoop,Spark,Storm,Kafka,人工智慧,機器學習,深度學習,專案實戰視訊教程 視訊課程包含: 38套大資料和人工智慧高階課包含:大資料,雲端計算,架構,資料探勘實戰,實時推薦系統實戰,電視收視率專案實戰,實時流統計專案實戰,離線電

機器學習 深度學習資料彙總(含文件資料程式碼等) 三

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Python_基礎(命名資料型別迴圈)

與變數名相關 數字,字母,下劃線 不能以數字為開頭 不能是Python中的中的關鍵字 and                elif  &nbs

HashTable與HashMap的區別資料結構類檔案結構原始碼分析

轉載https://www.imooc.com/article/details/id/23015 與HashMap的區別 1 HashMap是非同步的,沒有對讀寫等操作進行鎖保護,所以是執行緒不安全的,在多執行緒場景下會出現資料不一致的問題。而HashTable是同步的,所有的讀寫等操作都進

通過SAP函式組GOX_OBJECTS_GENERATE中的函式建立資料物件(域資料元素表)

  *&---------------------------------------------------------------------* *& Report ZRCP10 *&-------------------------

java流:列印流序列流資料記憶體流

列印流:位元組列印流PrintStream package com.qianfeng.test; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; im

小程式頁面跳轉資料傳遞json字串轉物件並使用

小程式頁面跳轉,資料傳遞,json字串轉物件並使用 1.新建一個資料夾和page,隨便取名,我這裡是qrcontent,如下: 2.頁面跳轉並傳遞資料 index.js跳轉qrcontent.js,在index.js方法中新增程式碼: success: functi

rac遷移ocr,votedisk,引數檔案資料檔案控制檔案密碼檔案redoundotempasm磁碟

概述:資料庫沒有開啟歸檔,當前環境12.1。votedg(normal)遷移到dg_vote(external),把votedg下的磁碟新增到dg_vote中,並幹掉votedg 因為只建立了votedg磁碟組,cdb,pdb也建立在上面,過程還是比較複雜,因為資料庫很多檔案都放在voted

mysql中為使用者設定資料庫資料欄位(列)的訪問許可權

1、mysql中對指定使用者,授予某些資料庫,資料表或者欄位訪問許可權 語法: GRANT PRIVILEGES ON DATA.TABLE TO USERS; 溫馨提示: 授權後可以使用2中命令進行使用者許可權許可權,也可以直接重啟mysql程序方式進行許可權重新整理。 A

微信小程式開發--模板(template)使用資料載入點選互動

  微信小程式檢視層提供了 模板(template),可以在模板中定義程式碼片段,然後在不同的地方呼叫。結果在資料渲染那懵逼了。按照官網上對模板的說明和對資料的載入。 1、定義模板   使用name屬性,作為模板的名字。然後在<template/>內定義程式碼

java day22 IO流 序列流物件流資料列印流

22.01_IO流(序列流)(瞭解) 1.什麼是序列流 序列流可以把多個位元組輸入流整合成一個, 從序列流中讀取資料時, 將從被整合的第一個流開始讀, 讀完一個之後繼續讀第二個, 以此類推. 2.使用方式 整合兩個:

基於深度學習的CT影象肺結節自動檢測技術一——資料預處理(歸一化資料增強資料標記)

開發環境 Anaconda:jupyter notebook /pycharm pip install SimpleItk # 讀取CT醫學影象 pip install tqdm # 可擴充套件的Python進度條,封裝

Mysql資料庫的基本操作--資料庫資料資料的基本操作

- -資料庫的操作 連結資料庫:mysql -u使用者名稱 -p 密碼 退出資料庫:exit, quit, ctrl+d 檢視所有的資料庫:show databases; (注意命令後面要加分號 ;) 顯示時間:select now(); 顯示資料庫版

vue路由傳物件重新整理會報錯資料丟失用json字串解決

我的訂單頁面---------》訂單詳情頁面 我的訂單頁面: encodeURIComponent(JSON.stringify(this.detailMsg))------變成json字串,且加密 toDetail(index) { request.p

java se 學習筆記(1)識別符號資料型別陣列

準備瞭解一下java的基本語法,以解決學習的《軟體工程》《需求工程》《軟體測試》《視覺化》課程 學校所學mfc框架較為繁瑣。 Javac 原始檔,————》.class (二進位制),給jvm閱讀 //向主方法傳入引數, 引數1 引數2...(中間用空格隔開)

Python在金融資料分析和人工智慧中的應用

Python最近取得這樣的成功,而且未來似乎還會繼續下去,這有許多原因。其中包括它的語法、Python開發人員可用的科學生態系統和資料分析庫、易於和幾乎所有其它技術整合,以及其開源地位。——來自Yves Hilpisch的Python金融大資料分析(姚軍譯)。 自從1991它出現在程式設計場景中,比於其他程