安卓RV列表刷新

RecyclerView是一个常用的列表控件。一般来说,当项目的数据发生变化时,我们需要刷新当前项目。

如何刷新房车列表?基本上,有几种方法:


notifyDataSetChanged()

notifyItemChanged(int位置)

notifyItemChanged(int position,@Nullable Object payload)


一般来说,一个项目由多个控件组成,如Button、CheckBox、TextView、ImageView、ViewGroup等。当我们点击一个条目的控件时,RV需要重新计算布局并刷新视图来响应交互。假设一个项目包含n个多个控件,如果调用notifyItemChanged(int position),项目中的每个控件都需要重新显示,无形中增加了内存和性能的损失。

即使不考虑内存和性能,那么有些效果是我们无法接受的。物品刷新时,会导致内部图片或物品闪烁一次。

以我的精神食粮起点为例,如下


这就是为什么我们需要使用像Payload和Diff这样的刷新方法。

让我们来看看它们是如何使用的。

1.有效负载的刷新

我们通过notifyitemchanged (intposition,@ nullableobjectpayload)刷新指定索引的项。

RV的适配器中的OnBindViewHolder可以接收payloads参数,它是一个List对象,不为null,但可以为空。

public void onBindViewHolder(VH holder,int position,List payloads) {

onBindViewHolder(持有者,位置);

}


如果没有有效载荷,调用notifyItemChanged时,RV会调用OnBindViewHolder (holder,position)用当前的数据变化更新该项,这将触发视图在整个项中位置的重新布局和计算。在这种情况下,只要其中一个视图的状态发生变化,整个项目最终都需要重新放置。

比如上面的例子,在评论列表中,我只喜欢了第一项,我们告诉RV该项中的like文本是通过payload改变的,所以我们只需要处理like文本的改变。

第二,Diff的刷新和快速实现

每个有效负载都必须写一次,如果我们在调用notifyItemChanged时出错了怎么办?有没有办法让程序自动管理,让程序替我们记录有效载荷?

还不如帮我们自动排序!

是的,我们先来看看自动排序方法:SortedList方法。

SortedList,顾名思义,是一个有序列表。适用于列表有序不重复的场景。而SortedList会帮你比较数据的差异,定向刷新数据。而不是简单粗暴的notifyDataSetChanged()。

例如,我们定义了一个城市排序的对象:

公共类城市{


private int id

私有字符串cityName

私有字符串首字母;


...

}


然后在Adapte中使用的时候,就不需要Arrylist了。您需要使用已排序的集合和新的对象SortedList对集合进行排序。

公共类SortedAdapter扩展RecyclerView。适配器{


//数据源使用SortedList

private SortedList mSortedList

私人LayoutInflater mInflater


public sorted adapter(Context m Context){

min flater = layoutinflater . from(m context);

}


public void setsorted list(sorted list mSortedList){

this.mSortedList = mSortedList


}


/**

*批量更新操作,例如:

*

* msortedlist . beginbatchedupdates();

*尝试{

* mSortedList.add(项目1)

* mSortedList.add(项目2)

* mSortedList.remove(第3项)

* ...

* }最后{

* msortedlist . endbatchedudates();

* }

*

*/

public void addData(List mData) {

msorted list . beginbatchedupdates();

msortedlist . addall(mData);

msortedlist . endbatchedudates();

}


/**

*删除项目

*/

public void remove data(int index){

msortedlist . remove itemat(index);

}


/**

*清除收藏

*/

公共void clear() {

msortedlist . clear();

}


@覆盖

@NonNull

公共分类适配器。view holder oncreateview holder(@ NonNull view group parent,int viewType) {

返回新的view holder(min flater . inflate(r . layout . item _ test,parent,false));

}


@覆盖

public void onBindViewHolder(@ NonNull sorted adapter。取景器支架,最终中间位置){

// 。。。

}


@覆盖

public int getItemCount() {

返回msorted list . size();

}



公共类ViewHolder扩展RecyclerView。取景框{

公共视图持有者(查看项目视图){

超级(item view);

}



}

}

复制代码

使用时:

recycler view mRecyclerView = findViewById(r . id . RV);

mrecyclerview . setlayoutmanager(new LinearLayoutManager(this));

mSortedAdapter = new sorted adapter(this);

// SortedList初始化

SortedListCallback mSortedListCallback = new SortedListCallback(mSortedAdapter);

sorted list mSortedList = new sorted list(city . class,mSortedListCallback);


msortedadapter . setsortedlist(mSortedList);

mrecyclerview . set adapter(mSortedAdapter);


//添加数据

...

复制代码

这样可以实现自动排序和列表刷新,比notifyDataSetChanged的暴力刷新更优雅。但不具备有效载荷的功能。这次刷新只是刷新了整个RV中的部分物品,但还是刷新了整个物品。

有没有什么方法可以对有效载荷进行不同的排序和刷新?

当然,DiffUtil的方式诞生了,几个常用的相关类是diff util asynclistDiffList Adapter(快速实现的封装类)。

DiffUtil可以实现有效载荷的排序和部分刷新:


当一个项目的位置改变时,排序逻辑被触发,并且有移除和添加的动画。

当项目的位置不变而内容发生变化时,会触发有效负载的本地刷新。

计算子线程中的DiffResult并刷新主线程中的RecyclerView。


什么是AsyncListDiffer,为什么需要它?

实际上,AsyncListDiffer集成了AsyncListUtil+DiffUtil的功能。因为diffutil在计算数据差异DiffUtil时是一个耗时的操作。Calculate Diff (mdiffcallback),我们需要放在子线程中处理,最后在主线程中刷新。为了方便我们开发者,Google直接提供了AsyncListDiffer供我们直接使用。好像Google怕我们开发者不会用子线程,就直接给我们写了。

ListAdapter是什么鬼?为什么越来越复杂?

实际上,谷歌喜欢把简单的事情复杂化。如果用AsyncListDiffer来实现,虽然不用担心子线程,但还是需要定义对象、集合和添加数据的方法,比如addNewData,调用mDiffer.submitList()来实现。

谷歌还怕我们不会用!直接简化了AsyncListDiffer的使用,直接提供了ListAdapter包装类。AsyncListDiffer的使用是内部封装的,我们的RV-Adapter在使用时可以直接继承ListAdapter。

AsyncListDiffer的功能,甚至内部设置数据的方法,都给我们提供了很好的。谷歌真是我们的好爸爸!伤透了我们开发商的心。

那么它们都是如何工作的呢?

不管怎样,我们需要定义自己的困难。回调毕竟就算程序帮我们排序和区分,我们也要告诉程序排序和区分的规则吧?

公共类MyDiffUtilItemCallback扩展DiffUtil。ItemCallback {


/**

*是同一个对象吗?

*/

@覆盖

public boolean areItemsTheSame(@ NonNull TestBean old item,@NonNull TestBean newItem) {

return ol ditem . getid()= = new item . getid();

}

/**

*是同样的内容吗?

*/

@覆盖

public boolean areContentsTheSame(@ NonNull TestBean old item,@NonNull TestBean newItem) {

返回oldItem.getName()。equals(new item . getname());

}


/**

*当AreItemTheName()返回true,areContentsTheSame()返回false时调用,也就是说两个对象代表的数据是一个,

*但内容已经更新。此方法用于定向刷新,可选。

*/

@Nullable

@覆盖

public Object getchange payload(@ NonNull TestBean old item,@NonNull TestBean newItem) {

Bundle payload = new Bundle();


如果(!oldItem.getName()。equals(new item . getname()){

payload.putString("KEY_NAME ",new item . getname());

}


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

//如果没有变化,则为空。

返回null

}

返回有效载荷;

}

}

复制代码

我们应该选择哪种方案来具体实现Diff?其实这三种方法都可以实现。这里我们先用AsyncListDiffer方法来实现。</p>