RecyclerView的notify方法及其payload参数

 

列表的数据更新,通常有两种更新事件,一种是item change event,条目改变事件,就是item中有数据变化了;一种是structural change event,结构改变事件,即插入、删除或者移动了一些item。

这些变化在RecycleView.Adapter中就可以单独更新,提高效率,也更方便一点。RecyclerView.Adapter中有多个notify方法,用户可以有选择的使用。

在列表显示中,可以分为两个部分,一个是list,是数据的存储信息,我们从list取得要显示的数据然后显示出来;另一个是items,是已经在屏幕中显示出来的条目信息。通常,我们在 onBindViewHolder方法里面去绑定

一、

RecyclerView.Adapter的notify主要有以下几个:

1.

void notifyDataSetChanged ()

notifyDataSetChanged是与BaseAdapter中的更新方法相同的。通知用户有数据都改变了,但是并未指定改变的内容,所以我们只能对所有的数据进行更新,包括item和structural 。

2.

void notifyItemChanged (int position) //单形参

void notifyItemChanged (int position, Object payload) // //两个形参

notifyItemChanged属于item change event。通知用户某一项item中的数据改变了,要进行更新,更新之后,索引不变。关于payload的用法,请往下看。

以下四个调用时等价的:

notifyItemchange(position)    ==   notifyItemchange(position,null)   

==  notifyItemRangechange(position,1)   ==  notifyItemRangechange(position,1,null) 

这是因为在源码中,notifyItemchange是调用notifyItemRangechange来实现的。

è¿éåå¾çæè¿°

3.

void notifyItemInserted (int position)

 notifyItemInserted属于structural change event。这个方法通知用户有新的item插入进来了,并且由动画,可以使用默认的,也可以自定义。position位置上的是新插入的item,而从原来的position位置开始往后的item,索引全部都+1.

用法一般如下:

list.add(i, data);  //list的插入

adapter.notifyItemInserted(i);  //item的插入,但是i后面的item的position没有变

adapter.notifyItemRangeChanged(i, adapter.getItemCount()-i); // 更新从i开始的item的position

为什么要刷新position为2以后的数据呢?因为,在position为2的位置插入了一条数据后,新数据的position变成了2,那原来的position为2的应该变成了3,3的应该变成了4,所以2以后的所有数据的position都发生了改变,所以需要把position2以后的数据都要刷新。

如果这里使用notifyDataSetChanged()来刷新屏幕上显示的所有item可以吗?结果不会出错,但是会有一个问题,前面调用了notifyItemInserted()方法后会在执行动画,如果你调用notifyDataSetChanged()刷新屏幕上显示的所有item的话,必然也会刷新当前正在执行动画的那个item,这样导致的结果是,前面的动画还没执行完,它马上又被刷新了,动画就看不见了。所以只要刷新2以后的item就可以了。

(这段摘自安卓笔记侠-RecyclerView中notifyDataSetChanged刷新总结

4.

void notifyItemMoved (int fromPosition, int toPosition)

 属于structural change event。用于item移动的通知。item从fromPosition位置挪到了toPosition位置。

说明一点,moved不是将两个数据交换,而是将其中一个fromPosition位置的依次向toPosition的方向挪,直到挪到toPosition为止。调用notifyItemMoved方法后,fromPosition和toPosition之间的item的position全部都发生了变化。可以用下面的方法刷新:

if (toPosition == fromPosition)return;

notifyItemMoved(fromPosition, toPosition);

notifyItemRangeChanged(Math.min(fromPosition, toPosition), Math.abs(fromPosition - toPosition) +1);

5.

void notifyItemRemoved (int position)

  属于structural change event。通知用户有在position位置上的item被删除了。后面的item索引全部-1。

 用法一般为:

    public void remove(int position) {
        mDataList.remove(position); //数组长度-1,但是item的长度还没有变

        notifyItemRemoved(position); // 会有删除的动画效果,但是没有调用onBindViewHolder方法没有调用,position没有刷新
       
        notifyItemRangeChanged(position, mDataList.size() - position); //对position进行刷新
       
    }

 6.

void notifyItemRangeChanged (int positionStart, int itemCount, Object payload)

void notifyItemRangeChanged (int positionStart, int itemCount)

 属于item change event,并且是一个范围性的更新。从positionStart开始,有itemCount个item需要更新。更新之后,索引不变。这里的刷新,是直接调用onBindViewHolder方法,对范围内的每个item的position进行了刷新。关于payload的用法,请往下看。

以下调用等价:

notifyItemRangechange(position,1)    ==   notifyItemRangechange(position,1,null)   

7.

void notifyItemRangeInserted (int positionStart,  int itemCount)

属于structural change event,并且是一个范围性的更新。这个方法通知用户有itemCount个新的item插入进来了。position位置上的是新插入的item,而从原来的position位置开始往后的item,索引全部都+itemCount。

8.

void notifyItemRangeRemoved (int positionStart, int itemCount)

属于structural change event,并且是一个范围性的更新。通知用户有itemCount个item被删除了。后面的item索引全部-itemCount。

 

二、

上面的方法中,有的方法含有payload参数。用法详解请参考云在千峰-使用 Payload 提高 RecyclerView 渲染效率

简单来说,就是进一步的细化了更新的部分,提高了效率。

上面的方法,当payload为null时,都是在更新整个item,系统回调

void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) 

方法进行item的更新;当payload不为null时(只要不为null就行,可以是任何值),系统会回调

void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List<Object> payloads)

方法,在这个方法中,我们就可以通过判断payload是否为空,有选择的对item中的任何控件进行更新。

具体用法如下:

    @Override
    public void onBindViewHolder(ViewHolder holder, int position, List<Object> payloads) {
        if (payloads.isEmpty()) {
            // payloads 为 空,说明是更新整个 ViewHolder 
            onBindViewHolder(holder, position);
        } else {
            // payloads 不为空,这只更新需要更新的 View 即可。
           ViewHolder viewHolder = (ViewHolder) holder;
           holder.tv.setText("Hello World!");
        }
    }

 

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值