Android的RV列表刷新詳解Payload與Diff方式異同_第1頁
Android的RV列表刷新詳解Payload與Diff方式異同_第2頁
Android的RV列表刷新詳解Payload與Diff方式異同_第3頁
Android的RV列表刷新詳解Payload與Diff方式異同_第4頁
Android的RV列表刷新詳解Payload與Diff方式異同_第5頁
已閱讀5頁,還剩23頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第Android的RV列表刷新詳解Payload與Diff方式異同目錄前言一、Payload的刷新二、Diff的刷新與快速實現(xiàn)方法三、DiffUtil的封裝小結(jié)

前言

RecyclerView是我們常用的列表控件,一般來說當Item的數(shù)據(jù)改變的時候我們需要刷新當前的Item。

如何刷新RV的列表?基本上有這幾種方式:

notifyDataSetChanged()

notifyItemChanged(intposition)

notifyItemChanged(intposition,@NullableObjectpayload)

一般來說一個item是由多個控件組成的,如Button、CheckBox、TextView、ImageView、ViewGroup等組合。當我們點擊item的某個控件時,RV需要重新計算布局、刷新視圖來響應(yīng)交互。假設(shè)一個item包含了N多個控件,如果調(diào)用notifyItemChanged(intposition)時,item中的每個控件都需要重新布局顯示,無形中加大了內(nèi)存和性能的損耗。

就算我們不考慮內(nèi)存和性能的問題,那么一些效果也是我們無法接受的,當item刷新的時候會導致內(nèi)部的圖片或item出現(xiàn)一次閃爍。

以我的精神糧食起點為例,如下

所以我們才需要用到類似Payload與Diff之類的刷新方式。

下面我們就一起看看它們是怎么使用的。

一、Payload的刷新

我們通過notifyItemChanged(intposition,@NullableObjectpayload)來刷新指定索引的item。

在RV的Adapter中的onBindViewHolder可以接收到payloads參數(shù),這個payloads參數(shù)是一個List對象,該對象不是null但可能是空的。

publicvoidonBindViewHolder(VHholder,intposition,ListObjectpayloads){

onBindViewHolder(holder,position);

通過Adapter的notifyXXX函數(shù)的帶有payload參數(shù)的函數(shù)可以設(shè)置payload對象,如:

publicfinalvoidnotifyItemChanged(intposition,Objectpayload){

mObservable.notifyItemRangeChanged(position,1,payload);

由于onBindViewHolder有重載的方法,如果使用了payloads的方式,那么我們需要做兼容,如果沒有payloads就去走整個item的刷新,如果有payloads那么我們就根據(jù)指定的payload去刷新指定的數(shù)據(jù)。

@Override

publicvoidonBindViewHolder(ViewHolderholder,intposition,ListObjectpayloads){

if(!payloads.isEmpty()payloads.get(0).equals("like")){

//如果是我們指定的payloads,那么就可以指定刷新

TipsBeanitem=mData.get(position);

holder.tvLikeNum.setText(R.id.tv_tips_like_num,item.likes_count0item.likes_count+"":"Like");

holder.tvLikeNum.setTextColor(R.id.tv_tips_like_num,item.likes_count0CommUtils.getColor(R.color.black):CommUtils.getColor(R.color.home_item_text_light_gray));

}else{

//如果沒有payloads,或者不是我們指定的,還是返回默認的整個刷新

super.onBindViewHolder(holder,position);

如果沒有payload,當調(diào)用notifyItemChanged時,RV會通過回調(diào)onBindViewHolder(holder,position)來更新當前數(shù)據(jù)變化的item,此時會觸發(fā)整個item中view的重新布局和計算位置,這樣的話只要是其中一個View狀態(tài)變化了,最終會導致整個item都需要重新布局一遍。

例如上述的例子,在評論的列表中,我只點贊了第一個item,我們就通過payload來告訴RV這個item中的like文本變化了,那么我們就只需要處理Like文本的變化。

二、Diff的刷新與快速實現(xiàn)方法

每一個payloads都要寫一次,然后我們在調(diào)用notifyItemChanged時萬一寫錯了怎么辦?有沒有一種方式能讓程序自動管理,讓程序幫我們記錄payloads?最好還能幫助我們自動排序!

有,我們先看看自動排序的方式:SortedList的方式

SortedList,顧名思義就是排序列表,它適用于列表有序且不重復的場景。并且SortedList會幫助你比較數(shù)據(jù)的差異,定向刷新數(shù)據(jù)。而不是簡單粗暴的notifyDataSetChanged()。

例如我們定義一個城市排序的對象:

publicclassCity{

privateintid;

privateStringcityName;

privateStringfirstLetter;

我們需要進行排序的規(guī)則定義

publicclassSortedListCallbackextendsSortedListAdapterCallbackCity{

publicSortedListCallback(RecyclerView.Adapteradapter){

super(adapter);

*排序條件

@Override

publicintcompare(Cityo1,Cityo2){

returno1.getFirstLetter().compareTo(o2.getFirstLetter());

*用來判斷兩個對象是否是相同的Item。

@Override

publicbooleanareItemsTheSame(Cityitem1,Cityitem2){

returnitem1.getId()==item2.getId();

*用來判斷兩個對象是否是內(nèi)容的Item。

@Override

publicbooleanareContentsTheSame(CityoldItem,CitynewItem){

if(oldItem.getId()!=newItem.getId()){

returnfalse;

returnoldItem.getCityName().equals(newItem.getCityName());

再然后在Adapte中使用的時候,不需要Arrylist,要用排序的集合,新的對象SortedList排序集合。

publicclassSortedAdapterextendsRecyclerView.AdapterSortedAdapter.ViewHolder{

//數(shù)據(jù)源使用SortedList

privateSortedListCitymSortedList;

privateLayoutInflatermInflater;

publicSortedAdapter(ContextmContext){

mInflater=LayoutInflater.from(mContext);

publicvoidsetSortedList(SortedListCitymSortedList){

this.mSortedList=mSortedList;

*批量更新操作,例如:

*pre

*mSortedList.beginBatchedUpdates();

*try{

*mSortedList.add(item1)

*mSortedList.add(item2)

*mSortedList.remove(item3)

*...

*}finally{

*mSortedList.endBatchedUpdates();

*/pre

publicvoidaddData(ListCitymData){

mSortedList.beginBatchedUpdates();

mSortedList.addAll(mData);

mSortedList.endBatchedUpdates();

*移除item

publicvoidremoveData(intindex){

mSortedList.removeItemAt(index);

*清除集合

publicvoidclear(){

mSortedList.clear();

@Override

@NonNull

publicSortedAdapter.ViewHolderonCreateViewHolder(@NonNullViewGroupparent,intviewType){

returnnewViewHolder(mInflater.inflate(R.layout.item_test,parent,false));

@Override

publicvoidonBindViewHolder(@NonNullSortedAdapter.ViewHolderholder,finalintposition){

//。。。

@Override

publicintgetItemCount(){

returnmSortedList.size();

publicclassViewHolderextendsRecyclerView.ViewHolder{

publicViewHolder(ViewitemView){

super(itemView);

使用的時候:

RecyclerViewmRecyclerView=findViewById(R.id.rv);

mRecyclerView.setLayoutManager(newLinearLayoutManager(this));

mSortedAdapter=newSortedAdapter(this);

//SortedList初始化

SortedListCallbackmSortedListCallback=newSortedListCallback(mSortedAdapter);

SortedListmSortedList=newSortedList(City.class,mSortedListCallback);

mSortedAdapter.setSortedList(mSortedList);

mRecyclerView.setAdapter(mSortedAdapter);

//添加數(shù)據(jù)

這樣確實就能實現(xiàn)自動排序,刷新列表了,相對notifyDataSetChanged的暴力刷新,優(yōu)雅一點。但是它沒有payload的功能,這個刷新只是刷新的是整個RV中的部分Item,但還是刷新整個item啊。

有沒有辦法既能排序又能payload差異化刷新的方式呢?

肯定有哇,DiffUtil的方式就此誕生,常用的相關(guān)的幾個類為DiffUtilAsyncListDifferListAdapter(用于快速實現(xiàn)的封裝類)

DiffUtil能實現(xiàn)排序加payload局部刷新的功能:

當某個item的位置變化,觸發(fā)排序邏輯,有移除和添加的動畫。當某個item的位置不變,內(nèi)容變化,觸發(fā)payload局部刷新。在子線程中計算DiffResult,在主線程中刷新RecyclerView。

AsyncListDiffer又是什么東西,為什么需要它。

其實AsyncListDiffer就是集成了AsyncListUtil+DiffUtil的功能,由于DiffUtil在計算數(shù)據(jù)差異DiffUtil.calculateDiff(mDiffCallback)是一個耗時操作,需要我們放到子線程去處理,最后在主線程刷新,為了我們開發(fā)者更加的方便,谷歌直接提供了AsyncListDiffer方便我們直接使用??磥砉雀枋桥挛覀冮_發(fā)者不會使用子線程,直接給我們寫好了。

ListAdapter又是個什么鬼?怎么越來越復雜了?

其實谷歌就喜歡把簡單的東西復雜化,如果我們使用AsyncListDiffer去實現(xiàn)的話,雖然不用我們操心子線程了,但是還是需要我們定義對象、集合、添加數(shù)據(jù)的方法,如addNewData,里面調(diào)用mDiffer.submitList()才能實現(xiàn)。

谷歌還是怕我們不會用吧!直接把AsyncListDiffer的使用都給簡化了,直接提供了ListAdapter包裝類,內(nèi)部對AsyncListDiffer的使用做了一系列的封裝,使用的時候我們的RV-Adapter直接繼承ListAdapter即可實現(xiàn)AsyncListDiffer的功能,內(nèi)部連設(shè)置數(shù)據(jù)的方法都給我們提供好了。谷歌真的是我們的好爸爸!為我們開發(fā)者操碎了心。

那它們都到底怎么使用呢?

不管什么方式,我們都需要定義好自己的DiffUtil.CallBack,畢竟就算讓程序幫我們排序和差分,我們也得告訴程序排序的規(guī)則和diff的規(guī)則,是吧!

publicclassMyDiffUtilItemCallbackextendsDiffUtil.ItemCallbackTestBean{

*是否是同一個對象

@Override

publicbooleanareItemsTheSame(@NonNullTestBeanoldItem,@NonNullTestBeannewItem){

returnoldItem.getId()==newItem.getId();

*是否是相同內(nèi)容

@Override

publicbooleanareContentsTheSame(@NonNullTestBeanoldItem,@NonNullTestBeannewItem){

returnoldItem.getName().equals(newItem.getName());

*areItemsTheSame()返回true而areContentsTheSame()返回false時調(diào)用,也就是說兩個對象代表的數(shù)據(jù)是一條,

*但是內(nèi)容更新了。此方法為定向刷新使用,可選。

@Nullable

@Override

publicObjectgetChangePayload(@NonNullTestBeanoldItem,@NonNullTestBeannewItem){

Bundlepayload=newBundle();

if(!oldItem.getName().equals(newItem.getName())){

payload.putString("KEY_NAME",newItem.getName());

if(payload.size()==0){

//如果沒有變化就傳空

returnnull;

returnpayload;

那個Diff的具體實現(xiàn)我們選用哪一種方案呢?其實三種方式都是可以實現(xiàn)的,這里我們先使用AsyncListDiffer的方式來實現(xiàn)。

上面關(guān)于AsyncListDiffer的介紹我們說過了,雖然不需要我們實現(xiàn)異步操作了,但是我們還是需要實現(xiàn)對象、集合、添加數(shù)據(jù)的方法等。

示例如下:

publicclassAsyncListDifferAdapterextendsRecyclerView.AdapterAsyncListDifferAdapter.ViewHolder{

privateLayoutInflatermInflater;

//數(shù)據(jù)的操作由AsyncListDiffer實現(xiàn)

privateAsyncListDifferTestBeanmDiffer;

publicAsyncListDifferAdapter(ContextmContext){

//初始化AsyncListDiffe

mDiffer=newAsyncListDiffer(this,newMyDiffUtilItemCallback());

mInflater=LayoutInflater.from(mContext);

//添加數(shù)據(jù)傳對象和對象集合都可以

publicvoidaddData(TestBeanmData){

ListTestBeanmList=newArrayList();

mList.addAll(mDiffer.getCurrentList());

mList.add(mData);

mDiffer.submitList(mList);

publicvoidaddData(ListTestBeanmData){

//由于DiffUtil是對比新舊數(shù)據(jù),所以需要創(chuàng)建新的集合來存放新數(shù)據(jù)。

//實際情況下,每次都是重新獲取的新數(shù)據(jù),所以無需這步。

ListTestBeanmList=newArrayList();

mList.addAll(mData);

mDiffer.submitList(mList);

//刪除數(shù)據(jù),要先獲取全部集合,再刪除指定的集合,再提交刪除之后的集合

publicvoidremoveData(intindex){

ListTestBeanmList=newArrayList();

mList.addAll(mDiffer.getCurrentList());

mList.remove(index);

mDiffer.submitList(mList);

publicvoidclear(){

mDiffer.submitList(null);

@Override

@NonNull

publicAsyncListDifferAdapter.ViewHolderonCreateViewHolder(@NonNullViewGroupparent,intviewType){

returnnewViewHolder(mInflater.inflate(R.layout.item_test,parent,false));

@Override

publicvoidonBindViewHolder(@NonNullViewHolderholder,intposition,@NonNullListObjectpayloads){

if(payloads.isEmpty()){

onBindViewHolder(holder,position);

}else{

Bundlebundle=(Bundle)payloads.get(0);

holder.mTvName.setText(bundle.getString("KEY_NAME"));

@Override

publicvoidonBindViewHolder(@NonNullAsyncListDifferAdapter.ViewHolderholder,finalintposition){

TestBeanbean=mDiffer.getCurrentList().get(position);

holder.mTvName.setText(bean.getName());

@Override

publicintgetItemCount(){

returnmDiffer.getCurrentList().size();

staticclassViewHolderextendsRecyclerView.ViewHolder{

......

由于Diff.Callback我們已經(jīng)在Adapter內(nèi)部已經(jīng)初始化了,所以使用的時候我們直接像普通的RV設(shè)置Adapter一樣即可。

在更新數(shù)據(jù)的時候我們使用Adapter定義的addData和removeData即可完成Diff刷新。

使用ListAdapter會怎樣?

如果覺得使用AsyncListDiffer都嫌棄麻煩的話,我們直接使用ListAdapter也能實現(xiàn)。

由于我們還是需要一個List集合去保存我們的數(shù)據(jù),我們就能對ListAdapter再做一個簡單的基類封裝。

publicabstractclassBaseRVDifferAdapterT,VHextendsRecyclerView.ViewHolderextendsListAdapterT,VH{

protectedContextmContext;

protectedLayoutInflatermInflater;

protectedListTmDatas=newArrayList();

publicBaseRVDifferAdapter(Contextcontext,DiffUtil.ItemCallbackTcallback){

super(callback);

mContext=context;

mInflater=LayoutInflater.from(mContext);

//設(shè)置數(shù)據(jù)源

protectedvoidsetData(ListTlist){

mDatas.clear();

mDatas.addAll(list);

ListTmList=newArrayList();

mList.addAll(mDatas);

submitList(mList);

//添加數(shù)據(jù)源

protectedvoidaddData(ListTlist){

mDatas.addAll(list);

ListTmList=newArrayList();

mList.addAll(mDatas);

submitList(mList);

//刪除制定索引數(shù)據(jù)源

protectedvoidremoveData(intindex){

mDatas.remove(index);

ListTmList=newArrayList();

mList.addAll(mDatas);

submitList(mList);

//清除全部數(shù)據(jù)

protectedvoidclear(){

mDatas.clear();

submitList(null);

//獲取adapter維護的數(shù)據(jù)集合

protectedListTgetAdapterData(){

returnmDatas;

我們實現(xiàn)Adater的方法就如下:

publicclassMyListAdapterextendsBaseRVDifferAdapterTestBean,MyListAdapter.ViewHolder{

publicMyListAdapter(Contextcontext){

super(context,newMyDiffUtilItemCallback());

@Override

@NonNull

publicMyListAdapter.ViewHolderonCreateViewHolder(@NonNullViewGroupparent,intviewType){

returnnewViewHolder(mInflater.inflate(R.layout.item_test,parent,false));

@Override

publicvoidonBindViewHolder(@NonNullViewHolderholder,intposition,@NonNullListObjectpayloads){

if(payloads.isEmpty()){

onBindViewHolder(holder,position);

}else{

Bundlebundle=(Bundle)payloads.get(0);

holder.mTvName.setText(bundle.getString("KEY_NAME"));

@Override

publicvoidonBindViewHolder(@NonNullMyListAdapter.ViewHolderholder,finalintposition){

TestBeanbean=getItem(position);

holder.mTvName.setText(bean.getName());

staticclassViewHolderextendsRecyclerView.ViewHolder{

TextViewmTvName;

ViewHolder(ViewitemView){

super(itemView);

mTvName=itemView.findViewById(R.id.tv_name);

在我們自己的Adpater中,我們還是需要初始化我們自己的Diff.Callback的。那么在使用的時候也就和普通的RV設(shè)置Adapter是一樣的。

如下:

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_sorted_list);

RecyclerViewmRecyclerView=findViewById(R.id.rv);

mRecyclerView.setLayoutManager(newLinearLayoutManager(this));

mAsyncListDifferAdapter=newAsyncListDifferAdapter(this);

mRecyclerView.setAdapter(mAsyncListDifferAdapter);

initData();

privatevoidaddData(){

ListTestBeanmList=newArrayList();

for(inti=10;ii++){

mList.add(newTestBean(i,"Item"+i));

mMyListAdapter.addData(mList);

privatevoidinitData(){

ListTestBeanmList=newArrayList();

for(inti=0;ii++){

mList.add(newTestBean(i,"Item"+i));

mMyListAdapter.setData(mList);

privatevoidupdateData(){

ListTestBeanmList=newArrayList();

for(inti=20;ii++){

mList.add(newTestBean(i,"Item"+i));

mMyListAdapter.addData(mList);

是不是可以無腦使用Diff的方式呢?也不是,當一些普通長列表我們使用默認的RV-Adapter就行了,加載更多,往源數(shù)據(jù)上面加數(shù)據(jù),并不涉及到很多數(shù)據(jù)源改變的也沒必要使用Diff。

那么哪里使用?比如IM的會話列表,長期變動的數(shù)據(jù),比如評論區(qū)域熱評區(qū)的數(shù)據(jù)切換時,比如我們的Android掘金App:

直接暴力的切換數(shù)據(jù)源然后notifyDataSetChanged,這樣就會整個頁面閃爍。而對于這些特定的一些場景,我們使用Diff的功能,就會感覺更加的流暢,體驗會好一點哦!

三、DiffUtil的封裝

既然AsyncListDiffer和ListAdapter都是快速實現(xiàn)的方式,那我們直接使用基本DiffUtil行不行?

當然可以,我不想直接使用ListAdapter,我就想用RV.Adapter,因為我有其他的封裝與擴展,我自己會使用異步線程,我不需要你幫我管理,我不需要使用你的AsyncListDiffer幫我管理我的List對象。

我們可以直接使用基本的DiffUtil。真實使用下來也不是很復雜,只需要做一點點的封裝也能很方便的實現(xiàn)邏輯。

先寫一個Differ的配置文件,內(nèi)部可配置主線程,異步線程,和必備的DiffUtil.Callback:

classMyAsyncDifferConfigT(

@SuppressLint("SupportAnnotationUsage")

@RestrictTo(RestrictTo.Scope.LIBRARY)

valmainThreadExecutor:Executor,

valbackgroundThreadExecutor:Executor,

valdiffCallback:DiffUtil.ItemCallbackT){

classBuilderT(privatevalmDiffCallback:DiffUtil.ItemCallbackT){

companionobject{

privatevalsExecutorLock=Any()

privatevarsDiffExecutor:Executor=null

privatevarmMainThreadExecutor:Executor=null

privatevarmBackgroundThreadExecutor:Executor=null

funsetMainThreadExecutor(executor:Executor):BuilderT{

mMainThreadExecutor=executor

returnthis

funsetBackgroundThreadExecutor(executor:Executor):BuilderT{

mBackgroundThreadExecutor=executor

returnthis

funbuild():MyAsyncDifferConfigT{

if(mBackgroundThreadExecutor==null){

synchronized(sExecutorLock){

if(sDiffExecutor==null){

sDiffExecutor=Executors.newSingleThreadExecutor()

mBackgroundThreadExecutor=sDiffExecutor

returnMyAsyncDifferConfig(

mMainThreadExecutor,

mBackgroundThreadExecutor!!,

mDiffCallback)

重點是定義一個自己的AsyncDiffer,內(nèi)部使用DiffUtil來計算差分。

classMyAsyncDifferT(

privatevaladapter:RecyclerView.Adapter*,

privatevalconfig:MyAsyncDifferConfigT

privatevalmUpdateCallback:ListUpdateCallback=AdapterListUpdateCallback(adapter)

privatevarmMainThreadExecutor:Executor=config.mainThreadExecutor:MainThreadExecutor()

privatevalmListeners:MutableListListChangeListenerT=CopyOnWriteArrayList()

privatevarmMaxScheduledGeneration=0

privatevarmList:ListT=null

privatevarmReadOnlyList=emptyListT()

privateclassMainThreadExecutorinternalconstructor():Executor{

valmHandler=Handler(Looper.getMainLooper())

overridefunexecute(command:Runnable){

mHandler.post(command)

fungetCurrentList():ListT{

returnmReadOnlyList

@JvmOverloads

funsubmitList(newList:MutableListT,commitCallback:Runnable=null){

valrunGeneration:Int=++mMaxScheduledGeneration

if(newList==mList){

commitCallback.run()

return

valpreviousList=mReadOnlyList

if(newList==null){

valcountRemoved=mList.size:0

mList=null

mReadOnlyList=emptyList()

mUpdateCallback.onRemoved(0,countRemoved)

onCurrentListChanged(previousList,commitCallback)

return

if(mList==null){

mList=newList

mReadOnlyList=Collections.unmodifiableList(newList)

mUpdateCallback.onInserted(0,newList.size)

onCurrentListChanged(previousList,commitCallback)

return

valoldList:ListT=mListasListT

config.backgroundThreadExecutor.execute{

valresult=DiffUtil.calculateDiff(object:DiffUtil.Callback(){

overridefungetOldListSize():Int{

returnoldList.size

overridefungetNewListSize():Int{

returnnewList.size

overridefunareItemsTheSame(oldItemPosition:Int,newItemPosition:Int):Boolean{

valoldItem:T=oldList[oldItemPosition]

valnewItem:T=newList[newItemPosition]

returnif(oldItem!=nullnewItem!=null){

config.diffCallback.areItemsTheSame(oldItem,newItem)

}elseoldItem==nullnewItem==null

overridefunareContentsTheSame(oldItemPosition:Int,newItemPosition:Int):Boolean{

valoldItem:T=oldList[oldItemPosition]

valnewItem:T=newList[newItemPosition]

if(oldItem!=nullnewItem!=null){

returnconfig.diffCallback.areContentsTheSame(oldItem,newItem)

if(oldItem==nullnewItem==null){

returntrue

throwAssertionError()

overridefungetChangePayload(oldItemPosition:Int,newItemPosition:Int):Any{

valoldItem:T=oldList[oldItemPosition]

valnewItem:T=newList[newItemPosition]

if(oldItem!=nullnewItem!=null){

returnconfig.diffCallback.getChangePayload(oldItem,newItem)

throwAssertionError()

mMainThreadExecutor.execute{

if(mMaxScheduledGeneration==runGeneration){

latchList(newList,result,commitCallback)

privatefunlatchList(

newList:MutableListT,

diffResult:DiffUtil.DiffResult,

commitCallback:Runnable

valpreviousList=mReadOnlyList

mList=newList

mReadOnlyList=Collections.unmodifiableList(newList)

diffResult.dispatchUpdatesTo(mUpdateCallback)

onCurrentListChanged(previousList,commitCallback)

privatefunonCurrentListChanged(

previousList:ListT,

commitCallback:Runnable

for(listenerinmListeners){

listener.onCurrentListChanged(previousList,mReadOnlyList)

commitCallback.run()

//定義接口

interfaceListChangeListenerT{

funonCurrentListChanged(previousList:ListT,currentList:ListT)

funaddListListener(listener:ListChangeListenerT){

mListeners.add(listener)

funremoveListListener(listener:ListChangeListenerT){

mListeners.remove(listener)

funclearAllListListener(){

mListeners.clear()

然后我們可以用委托的方式配置,可以讓普通的RecyclerView.Adapter也能通過配置的方式選擇是否使用Differ。

實現(xiàn)我們的控制類接口

//設(shè)置別名簡化

typealiasIDifferT=IMyDifferControllerT

funTdiffer():MyDifferControllerT=MyDifferController()

interfaceIMyDifferControllerT{

funRecyclerView.Adapter*.initDiffer(config:MyAsyncDifferConfigT):MyAsyncDifferT

fungetDiffer():MyAsyncDifferT

fungetCurrentList():ListT

funsetDiffNewData(list:MutableListT,commitCallback:Runnable=null)

funaddDiffNewData(list:MutableListT,commitCallback:Runnable=null)

funaddDiffNewData(t:T,commitCallback:Runnable=null)

funremoveDiffData(index:Int)

funclearDiffData()

funRecyclerView.Adapter*.onCurrentListChanged(previousList:ListT,currentList:ListT)

在對控制類接口實例化,做一些具體的操作邏輯

classMyDifferControllerT:IMyDifferControllerT{

privatevarmDiffer:MyAsyncDifferT=null

overridefunRecyclerView.Adapter*.initDiffer(config:MyAsyncDifferConfigT):MyAsyncDifferT{

mDiffer=MyAsyncDiffer(this,config)

valmListener:MyAsyncDiffer.ListChangeListenerT=object:MyAsyncDiffer.ListChangeListenerT{

overridefunonCurrentListChanged(previousList:ListT,currentList:ListT){

this@initDiffer.onCurrentListChanged(previousList,currentList)

mDiffer.addListListener(mListener)

returnmDiffer!!

overridefungetDiffer():MyAsyncDifferT{

returnmDiffer

overridefungetCurrentList():ListT{

returnmDiffer.getCurrentList():emptyList()

overridefunsetDiffNewData(list:MutableListT,commitCallback:Runnable){

mDiffer.submitList(list,commitCallback)

overridefunaddDiffNewData(list:MutableListT,commitCallback:Runnable){

valnewList=mutableListOfT()

newList.addAll(mDiffer.getCurrentList():emptyList())

newList.addAll(list)

mDiffer.submitList(newList,commitCallback)

overridefunaddDiffNewData(t:T,commitCallback:Runnable){

valnewList=mutableListOfT()

newList.addAll(mDiffer.getCurrentList():emptyList())

newList.add(t)

mDiffer.submitList(newList,commitCallback)

overridefunremoveDiffData(index:Int){

valnewList=mutableListOfT()

newList.addAll(mDiffer.getCurrentList():emptyList())

newList.removeAt(index)

mDiffer.submitList(newList)

overridefunclearDiffData(){

mDiffer.submitList(null)

overridefunRecyclerView.Adapter*.onCurrentListChanged(previousList:ListT,currentList:ListT){

到此我們就能封裝一個DiffUtil的工具類了,我們可以選擇是否啟用Diff,例如我們不使用Diff,我們使用Adapter就是一個普通的Adaper

classMyDiffAdapter():RecyclerView.AdapterBaseViewHolder(){

privatevalmDatas=arrayListOfDemoDiffBean()

funaddData(list:ListDemoDiffBean){

mDatas.addAll(list)

notifyDataSetChanged()

overridefunonBindViewHolder(holder:BaseViewHolder,position:Int,payloads:MutableListAny){

if(!CheckUtil.isEmpty(payloads)(payloads[0]asString)=="text"){

YYLogUtils.w("差分刷新--------文本更新")

holder.setText(R.id.tv_job_text,mDatas[position].content)

}else{

onBindViewHolder(holder,position)

overridefunonBindViewHolder(holder:BaseViewHolder,position:Int){

YYLogUtils.w("默認數(shù)據(jù)賦值--------")

holder.setText(R.id.tv_job_text,mDatas[position].content)

overridefunonCreateViewHolder(parent:ViewGroup,viewType:Int):BaseViewHolder{

returnBaseViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_diff_jobs,parent,false))

overridefungetItemCount():Int{

returnmDatas.size

如果我們想啟動Diff的功能的時候,實現(xiàn)這個接口并委托實現(xiàn)即可啟用Diff。

classMyDiffAdapter():RecyclerView.AdapterBaseViewHolder(),IDifferDemoDiffBeanbydiffer(){

init{

initDiffer(MyAsyncDifferConfig.Builder(DiffDemoCallback()).build())

overridefunonBindViewHolder(holder:BaseVie

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論