admin管理员组文章数量:1611167
今天在看某个项目的源码的时候,无意间看到了 RecyclerView.Adapter 的 notifyItemChanged(int position, @Nullable Object payload)
方法,以前没有见过,后来自己查来之后,才知道这个是与 RV 的 Item 局部刷新有关的。
平时一般是用 notifyItemChanged(int position)
方法来进行局部刷新,但是这个局部刷新是通过回调 onBindViewHolder(@NonNull VH holder, int position)
该方法刷新指定的 item 的整个视图,如果该视图里面包含图片什么的,如果逻辑处理不当会导致图片也被重新刷新而使视图在效果闪一下。
而如果使用 notifyItemChanged(int position, @Nullable Object payload)
方法的话,则会回调 onBindViewHolder(@NonNull VH holder, int position,@NonNull List<Object> payloads)
方法,然后再该方法中就可以使用 payloads
参数来进行布局的刷新。
先用一个实例来演示一下:
假设 RV 中的 Item 包括一个 ImageView、两个 TextView,然后整个 Item 设置了一个点击事件,当 Item 被点击之后,就要为内部对应的两个 TextView 更新一下文本信息,如下图所示:
然后是省略之后的主要代码:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<ItemBean> data;
......
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
ItemBean itemBean=data.get(position);
holder.tv1.setText(itemBean.str1);
holder.tv2.setText(itemBean.str2);
holder.iv.setImageResource(R.mipmap.ic_launcher);
}
//要注意,当上下滑动 RV 导致 Item 因复用更新视图时,也会走该方法的,但是此时 payloads 为空
//所以应该注意在该方法中刷新的状态应该保存到 data 对应的 bean 中,使更新时能够读取到正确的状态而展现出正确的效果
//否则在上下滑动后,原位置的 Item 效果会退回到局部更新之前
@Override
public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
if (payloads.isEmpty()) {
//payloads 为 空,说明是更新整个 ViewHolder
onBindViewHolder(holder, position);
} else {
ItemBean itemBean=data.get(position);
//将需要刷新的状态保存到 ItemBean 对应的成员变量中
itemBean.str1 += (String) payloads.get(0);
itemBean.str2 += (String) payloads.get(1);
holder.tv1.setText(itemBean.str1);
holder.tv2.setText(itemBean.str2);
}
}
class ViewHolder extends RecyclerView.ViewHolder {
final TextView tv1,tv2;
final ImageView iv;
public ViewHolder(View itemView) {
super(itemView);
tv1 = itemView.findViewById(R.id.tv1);
tv2 = itemView.findViewById(R.id.tv2);
iv = itemView.findViewById(R.id.iv);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
notifyItemChanged(getAdapterPosition()," update for 1");
notifyItemChanged(getAdapterPosition()," update for 2");
}
});
}
}
}
这里需要注意的是,在 onBindViewHolder(ViewHolder holder, int position, List<Object> payloads)
中布局刷新时,同时需要将刷新的状态保存到对应的 bean 中,否则在上下滑动后,原 position 位置的 item 会退回到未局部刷新之前的状态。就像下图的效果:
@Override
public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
} else {
ItemBean itemBean=data.get(position);
// itemBean.str1 += (String) payloads.get(0);
// itemBean.str2 += (String) payloads.get(1);
// holder.tv1.setText(itemBean.str1);
// holder.tv2.setText(itemBean.str2);
//直接刷新该局部视图,而不保存相应的状态到 bean 中
holder.tv1.setText(itemBean.str1 + payloads.get(0));
holder.tv2.setText(itemBean.str2 + payloads.get(1));
}
}
之后,需要补充几点:
1、如果重写了 onBindViewHolder(ViewHolder holder, int position, List<Object> payloads)
方法,那么不管是 RV 在初始化时,还是在因为上下滑动而刷新时,都会走该方法(此时 payloads
为空),而不走 onBindViewHolder(ViewHolder holder, int position)
方法,因此,需要完善逻辑,在 payloads
为空时手动调用 onBindViewHolder(holder, position);
或者将原本 onBindViewHolder(holder, position);
的逻辑写到这里。
2、每一个具体的 position 都会在 onBindViewHolder(holder, position, payloads)
方法对应一个单独的 payloads
。
这一点测试一下即可知道,假设为 ItemView 的点击事件补充如下代码:
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
notifyItemChanged(getAdapterPosition()," update for 1 ->"+getAdapterPosition());
notifyItemChanged(getAdapterPosition()," update for 2 ->"+getAdapterPosition());
//补充的代码
notifyItemChanged(getAdapterPosition()+1," update for 1 ->"+(getAdapterPosition()+1));
notifyItemChanged(getAdapterPosition()+1," update for 2 ->"+(getAdapterPosition()+1));
}
});
则可以看到如下的效果:
position 为 1 和 2 分别刷新了对应的视图,且两者没有交叉。
3、假设在 notifyItemChanged(position, payload)
方法中传入的 payload
为 null,则会把 position
对应的 List<Object> payloads
清空,而在调用 onBindViewHolder(ViewHolder,int,List)
之前 notifyItemChanged(position, payload)
将不会起作用。
这个可以在源码的注释中了解到。
其中标记处的大致意思是:
notifyItemRangeChanged()中 payload == null 时将清除该项目上的所有现有的 payloads,并阻止将来
payloads 增加元素,直到调用 onBindViewHolder(ViewHolder,int,List)
然后通过实测也可以验证:
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
notifyItemChanged(getAdapterPosition()," update for 1 ->"+getAdapterPosition());
notifyItemChanged(getAdapterPosition()," update for 2 ->"+getAdapterPosition());
notifyItemChanged(getAdapterPosition(),null);
notifyItemChanged(getAdapterPosition()," update for 3 ->"+getAdapterPosition());
notifyItemChanged(getAdapterPosition()," update for 4 ->"+getAdapterPosition());
}
将 ItemView 的点击事件改成上述,然后运行,点击 Item,此时虽然会调用 onBindViewHolder(ViewHolder,int,List)
,但是 payloads.size() == 0
。
4、连续多次的调用 notifyItemChanged(position, payload)
,但是只会回调一次
onBindViewHolder(ViewHolder,int,List)
。具体原因需要分析源码,目前暂不深究。
本文标签: 方法notifyItemChangedINTRecyclerViewAdapter
版权声明:本文标题:有关RecyclerView.Adapter 的 notifyItemChanged(int position, @Nullable Object payload) 方法 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1728607350a1165622.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论