安卓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>