纠正:Android Attempt to write to field ‘int android.support.v7.widget.RecyclerView$ViewHolder...

最近发现recyclerview的一个异常,其他博客写的错的乱七八糟,在此纠正一下这个异常:


Attempt to write to field 'int android.support.v7.widget.RecyclerView$ViewHolder.mItemViewType' on a null object reference

 at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:5555)

....

首先教大家如何看这种没有报错行的崩溃日志:

1.打开崩溃的最后一行RecyclerView$Adapter.createViewHolder(由于电脑api版本和手机api版本可能不同,报错行号不一定是对的,自己参考报错信息ViewHolder.mItemViewType找到对应的行号)

public final VH createViewHolder(ViewGroup parent, int viewType) {
    TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG);
    final VH holder = onCreateViewHolder(parent, viewType);
    holder.mItemViewType = viewType;//可以看出是这行崩溃导致的
    TraceCompat.endSection();
    return holder;
}

2.空指针异常就是调用者为null,很明显我们来看holder怎么是null的

3.原来是onCreateViewHolder返回的,这就是我们天天自己重写的方法

4.所以此时检查自己的onCreateViewHolder必然有返回null的情况

有的人可能很费解:返回null是因为自己知道这是一个不可能出现的类型,RecyclerView是不是有bug?

在这个崩溃日志上我可以肯定的告诉你,肯定是你的代码问题

如下我列出最常见的错误代码:

1.先看看adapter类,有人会问:加了高大上的super做容错这样写有错吗(super.getItemViewType是0写不写没啥用)

            @Override
            protected BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType, LayoutInflater inflater) {
                switch (viewType) {
                    case TYPE_HEADER:
                        return new XXViewHolder(inflater.inflate(R.layout.vw_header, parent, false));
                    case TYPE_FOTTER:
                        return new YYViewHolder(inflater.inflate(R.layout.frag_skintest1, parent, false));
                    default:
                        return null;
                }
            }

            @Override
            public int getItemViewType(int position) {
                if (position == 0) {
                    return TYPE_HEADER;
                } else if (position<=mList.size()){
                    return TYPE_FOTTER;
                }
                return super.getItemViewType(position);
            }

2.这样写肯定也没错(勉强赞同?),但是下面的代码就是问题了

    public void httpData(){
        mList.clear();
        HttpUtils.postDialog(this,"",//网络请求框架
                MapUtils.getInstance(),
                DataBean.class,
                new OKHttpListener<DataBean>() {
                    @Override
                    public void onSuccess(DataBean bean) {//成功回调
                        mList.addAll(bean.data);
                        mAdapter.notifyDataSetChanged();
                    }
                });
    }

 很多人都喜欢在请求之前去clear自己的list,然后在网络请求完成之后再addAll,但是:

你在请求网络期间rv是不会每次都调用getItemCount的,这时候rv会认为count还是原来的(比如100)。

这段时间如果rv去getItemViewType(99),但你已经把你的list对象clear了,得到的结果自然是0了。

然后rv去拿这个0去onCreateViewHolder,null就此产生了


 3.正确的写法是:每次list发生变化的时候都应该刷新adapter来告诉rv数据发生变化了

public void httpData(){
        HttpUtils.postDialog(this,"",
                MapUtils.getInstance(),
                DataBean.class,
                new OKHttpListener<DataBean>() {
                    @Override
                    public void onSuccess(DataBean bean) {
                        mList.clear();
                        mList.addAll(bean.data);
                        mAdapter.notifyDataSetChanged();
                    }
                });
    }

 或者你也可以先clear,然后立即notify,等网络请求完成addAll,然后立即notify

4.还有比如getItemViewType和onCreateViewHolder的type不对应等其他问题(博主的脑洞也是有限的)。

首先找到可疑的位置,多debug就明白了

结论:

1.要学会正确的看错误日志

2.数据改变,adapter要及时刷新

3.不要看到未知错误就度娘,要学会debug,就算什么头绪都没有,挨个打断点最终也能找出问题


转载请注明出处:王能的博客纠正:Android Attempt to write to field 'int android.support.v7.widget.RecyclerView$ViewHolder..._王能的博客-CSDN博客

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值