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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weimingjue/article/details/79140697

最近发现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;
}
扫描二维码关注公众号,回复: 3339697 查看本文章

2.空指针异常知道吧:接着就看holder怎么是null的

3.onCreateViewHolder我就不用多解释了吧

4.检查自己的onCreateViewHolder肯定有返回null的情况

有的人可能很费解:返回null是因为自己知道这是一个不可能出现的类型,rv是不是有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,就算什么头绪都没有,挨个打断点最终也能找出问题


转载请注明出处:王能的博客https://blog.csdn.net/weimingjue/article/details/79140697

猜你喜欢

转载自blog.csdn.net/weimingjue/article/details/79140697