Android13 RecyclerView 清空操作和插入操作的 大坑:没有调用到onCreateViewHolder。

写在前面:本文适合熟练使用过RecyclerView,或者正在使用RecyclerView实现需求的开发人员阅读,没用过的话,读起来会比较难理解。

  首先背景介绍,我用RecyclerView,在对应Adapter的 onCreateViewHolder会做一些初始化操作,代码如下,对添加进RecyclerView的每一个Item做客制化,所以每次添加新Item,这里的初始化操作对我的需求来说必不可少。

    @NonNull
    @Override
    public T onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        myparent = parent;
        Log.d("MyNotificationService", " 走到onCreateViewHolder");

        Log.d("notification_xu_su ", "4、 onCreateViewHolder " + String.valueOf(viewType));

        if(list.size() != 0) {

            notification_center = LayoutInflater.from(mycontext).inflate(R.layout.notification_center, myparent, false);
            center_viewHolder = new Center_ViewHolder(notification_center);
            StaticVariableUtils.onCreate_To_onBind = true;
            return (T) center_viewHolder;
        }
        return null;

    }

  在我的理解中,不管是往RecyclerView中插入一个Item,还是从0开始往RecyclerView中添加Item,函数调用顺序都应是这样:先调用onCreateViewHolder ,之后调用onBindViewHolder 。 但是事实却不是这样,有些情况下会没有调用到onCreateViewHolder 导致我的代码异常,下面分两种异常情况来说明:

1、清空RecyclerView之后,从0添加新Item,不会调用onCreateViewHolder

  我用下面的代码清空RecyclerView:

STATIC_INSTANCE_UTILS.notificationCenterAdapter.list.clear();
STATIC_INSTANCE_UTILS.notificationCenterAdapter.notifyDataSetChanged();

  这是网上大多推荐的方法,但是后续如果再往RecyclerView中添加新Item,不会调用到onCreateViewHolder,我自己推测是RecyclerView 中对于列表大小的缓存没有清掉导致。

正确清空RecyclerView的操作如下:

                if (StaticVariableUtils.recyclerView.getChildCount() > 0 ) {
                    StaticVariableUtils.recyclerView.removeAllViews();
                    StaticVariableUtils.recyclerView.getRecycledViewPool().clear();//清除缓存
                    STATIC_INSTANCE_UTILS.notificationCenterAdapter.list.clear();
                    STATIC_INSTANCE_UTILS.notificationCenterAdapter.notifyDataSetChanged();
                }

2、调用 notifyItemInserted 方法往RecyclerView 的已有列表中插入一个Item

  注意,这里不是往RecyclerView末尾插值,末尾插值是不会出错的。我调用如下方法往某个postion插值:

    private void unfold(Center_ViewHolder center_viewHolder) {

        int mypostion = list.indexOf(center_viewHolder.notification_item);
        for(String string : list.get(list.indexOf(center_viewHolder.notification_item)).multiple_content) {
            //mypostion后面添加multiple_content个Item
            Log.d(TAG," unfold展开 "+String.valueOf(mypostion));
            Notification_Item notification_item = new Notification_Item();
            notification_item.appName = list.get(mypostion).appName;
            notification_item.Icon = list.get(mypostion).Icon;
            notification_item.content = string;
     
            list.add(mypostion ,notification_item);
            notifyItemInserted(mypostion);

        }
    }

  结果插值操作直接执行onBindViewHolder,跳过了onCreateViewHolder。针对这个问题,我各种网搜了一下,得到的最初结论如下:

    //notification_center_adapter.notifyItemInserted(list.size() - 1);
    //注意,notifyItemInserted有个比较恶心的特性:插入的位置在list末尾会按照 onCreateViewHolder ——> onBindViewHolder 的顺序调用
    //插入的位置如果在list中间,则会直接调用onBindViewHolder
    //

  其实这种结论也是不正确的,因为我发现有些时候插在列表中间也会调用到onCreateViewHolder,正确的结论如下:
  按照 onCreateViewHolder ——> onBindViewHolder
这个顺序调用的前提是,每次新增Item之后,整个list的大小都得比上一次大,如果小于或者等于上一次的大小,notifyItemInserted
方法会直接调用onBindViewHolder ,复用之前的RecyclerView.ViewHolder。举个例子,你先删除三条Item,又插入三条Item,不管你是在list中间、开头或者是末尾插入,onCreateViewHolder 都不会被调用到,因为前后两次list的size比较起来没有变大。而且 RecyclerView缓存中记录的list大小,应该是RecyclerView曾经到达过的最大值(这里没看过源码,存粹从使用表现上来看),举个例子,如果你往RecyclerView中曾经最多插入了20个Item,并且没有清理过缓存,那么就是说只有你往RecyclerView中插入第21个值才会触发调用onCreateViewHolder。

  那么问题来了,怎么在list没有增大的时候,进行插值操作,并且调用到onCreateViewHolder呢?答案和上述第一点清空异常的解决方法一样,notifyItemInserted之前,先清空RecyclerView的缓存。
  修改方法如下:

    private void unfold(Center_ViewHolder center_viewHolder) {

        int mypostion = list.indexOf(center_viewHolder.notification_item);
        for(String string : list.get(list.indexOf(center_viewHolder.notification_item)).multiple_content) {
            //mypostion后面添加multiple_content个Item
            Log.d(TAG," unfold展开 "+String.valueOf(mypostion));
            Notification_Item notification_item = new Notification_Item();
            notification_item.appName = list.get(mypostion).appName;
            notification_item.Icon = list.get(mypostion).Icon;
            notification_item.content = string;
          + StaticVariableUtils.recyclerView.getRecycledViewPool().clear();
            list.add(mypostion ,notification_item);
            notifyItemInserted(mypostion);

        }
    }

StaticVariableUtils.recyclerView.getRecycledViewPool().clear();

写在末尾:如果你的需求每次都必须在onCreateViewHolder中初始化一些功能才行,上述的处理方式就很有用。网上没有解决此种问题的文章,我就想着有必要记录一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苏苏码不动了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值