java.lang.IllegalArgumentException: itemView may not be null

在使用BaseRecyclerViewAdapterHelper库时,当数据达到273条时出现ANR。问题源于重写getItemViewType方法,注释掉此方法可以解决。问题的根本在于getItemViewType返回值与position相关,当position等于273时触发了一个错误条件。通过跟踪源码,发现是由于null参数引起的BaseViewHolder初始化问题。
摘要由CSDN通过智能技术生成

报错截图:

场景介绍:在使用recycleView 自动递增数据,且自动滚动到最新行; 当数据达到273条 时出现ANR;

项目中 全部的列表适配器使用的三方库:BaseRecyclerViewAdapterHelper (很早之前的项目)

代码:

public class LogRecyclerViewAdapter extends BaseQuickAdapter<LogBean,BaseViewHolder> {
    public LogRecyclerViewAdapter(int layoutResId, @Nullable List<LogBean> data) {
        super(layoutResId, data);
    }


    // 避免布局错乱
    @Override
    public int getItemViewType(int position) {
        Log.d(TAG, "getItemViewType1111: " +position);
        return position;
    }

    @Override
    protected void convert(BaseViewHolder helper, LogBean item) {
        String title = item.getTitle();
        String msg = item.getMsg();
        helper.setText(R.id.log_title_txt,title);
        helper.setText(R.id.log_msg_txt,msg);
        // 设置异常字体颜色
        if(msg.contains("异常")||msg.contains("中断")||msg.contains("失败")){
            helper.setTextColor(R.id.log_title_txt,Color.parseColor("#FF2C00"));
            helper.setTextColor(R.id.log_msg_txt, Color.parseColor("#FF2C00"));
        }

    }
}

解决 :根据报错提示,百度后解决 需要注释掉重写的getItemViewType 函数,其实是一个三方库的bug;

可参考:https://blog.csdn.net/lovelixue/article/details/103641023

为知其所以然 ,继续跟踪代码;

进入适配器继承的父类:BaseQuickAdapter该类继承自RecyclerView.Adapter<K> , 找到重写的getItemViewType 函数,getItemViewType的返回值 当有其他布局(头部脚部或空布局)时候返回值各自的常量;项目只是单item 没有添加其他View 代码会走

return getDefItemViewType(adjPosition);

该方法会重新定义getItemViewType的值而该值是position变量;

  @Override
    public int getItemViewType(int position) {
        if (getEmptyViewCount() == 1) {
            boolean header = mHeadAndEmptyEnable && getHeaderLayoutCount() != 0;
            switch (position) {
                case 0:
                    if (header) {
                        return HEADER_VIEW;
                    } else {
                        return EMPTY_VIEW;
                    }
                case 1:
                    if (header) {
                        return EMPTY_VIEW;
                    } else {
                        return FOOTER_VIEW;
                    }
                case 2:
                    return FOOTER_VIEW;
                default:
                    return EMPTY_VIEW;
            }
        }
        int numHeaders = getHeaderLayoutCount();
        if (position < numHeaders) {
            return HEADER_VIEW;
        } else {
            int adjPosition = position - numHeaders;
            int adapterCount = mData.size();
            if (adjPosition < adapterCount) {
                return getDefItemViewType(adjPosition);
            } else {
                adjPosition = adjPosition - adapterCount;
                int numFooters = getFooterLayoutCount();
                if (adjPosition < numFooters) {
                    return FOOTER_VIEW;
                } else {
                    return LOADING_VIEW;
                }
            }
        }
    }

 protected int getDefItemViewType(int position) {
        if (mMultiTypeDelegate != null) {
            return mMultiTypeDelegate.getDefItemViewType(mData, position);
        }
        return super.getItemViewType(position);
    }

回到:LogRecyclerViewAdapter 类中 ,业务代码在convert函数中实现 跟踪该函数,发现在BaseQuickAdapter中被onBindViewHolder调用,代码如下:它会获取holder的getItemViewType ,其值的已经分析过 取自position ,每次源数据新增一条position就会随之递增;其实报错的时候,还没有执行到该函数,我们需要查看recycleView的源码 执行该方法之前还执行了onCreateViewHolder 函数。

 @Override
    public void onBindViewHolder(K holder, int position) {
        //Add up fetch logic, almost like load more, but simpler.
        autoUpFetch(position);
        //Do not move position, need to change before LoadMoreView binding
        autoLoadMore(position);
        int viewType = holder.getItemViewType();

        switch (viewType) {
            case 0:
                convert(holder, getItem(position - getHeaderLayoutCount()));
                break;
            case LOADING_VIEW:
                mLoadMoreView.convert(holder);
                break;
            case HEADER_VIEW:
                break;
            case EMPTY_VIEW:
                break;
            case FOOTER_VIEW:
                break;
            default:
                convert(holder, getItem(position - getHeaderLayoutCount()));
                break;
        }
    }

@Override
    public K onCreateViewHolder(ViewGroup parent, int viewType) {
        K baseViewHolder = null;
        this.mContext = parent.getContext();
        this.mLayoutInflater = LayoutInflater.from(mContext);
        switch (viewType) {
            case LOADING_VIEW:
                baseViewHolder = getLoadingView(parent);
                break;
            case HEADER_VIEW:
                baseViewHolder = createBaseViewHolder(mHeaderLayout);
                break;
            case EMPTY_VIEW:
                baseViewHolder = createBaseViewHolder(mEmptyLayout);
                break;
            case FOOTER_VIEW:
                baseViewHolder = createBaseViewHolder(mFooterLayout);
                break;
            default:
                baseViewHolder = onCreateDefViewHolder(parent, viewType);
                bindViewClickListener(baseViewHolder);
        }
        baseViewHolder.setAdapter(this);
        return baseViewHolder;

    }

重点看下,switch 方法 ,会逐条遍历viewType,我们分别看case 条件值 ,分别是

public static final int HEADER_VIEW = 0x00000111;

public static final int LOADING_VIEW = 0x00000222;

public static final int FOOTER_VIEW = 0x00000333;

public static final int EMPTY_VIEW = 0x00000555;

是十六进制的魔法数字 ,case ==0 正常调用 0x00000111 转换成十进制是273 ,所以 当position 的值273的 时候,会进入第二个条件执行createBaseViewHolder (mHeaderLayout)此时的参数是null,

该函数表示通过反射的方式获取viewhold

protected K createBaseViewHolder(View view) {
        Class temp = getClass();
        Class z = null;
        while (z == null && null != temp) {
            z = getInstancedGenericKClass(temp);
            temp = temp.getSuperclass();
        }
        K k;
        // 泛型擦除会导致z为null
        if (z == null) {
            k = (K) new BaseViewHolder(view);
        } else {
            k = createGenericKInstance(z, view);
        }
        return k != null ? k : (K) new BaseViewHolder(view);
    }

进入BaseViewHolder 类中,该类继承自RecyclerView.ViewHolder,作用是封装了各种赋值函数,通过getView 获取到item的view 去赋值等。

 public ViewHolder(@NonNull View itemView) {
            if (itemView == null) {
                throw new IllegalArgumentException("itemView may not be null");
            }
            this.itemView = itemView;
        }

终于跟踪到报错的地方了。因为当初入参是null 因此条件判断进入itemView ==null ,就有了开始的IDE的输出报错;

完美的闭环

如有不完善的地方,譬如:recycleView源码部分,没有仔细说明,请多多担待;

抱拳;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值