使用RecyclerView遇到的 Inconsistency detected

转发请注明出处 : http://blog.csdn.net/snailbaby_soko/article/details/54342111

使用 RecyclerView 遇到的 Inconsistency detected 异常

(首先描述一下我当时项目的背景,我在一个RecyclerView的底部自己添加了一个布局,但这个布局是在 getItemCount >1的时候才会出现,= 0 的时候就隐藏的。简单来说,就是动态添加隐藏底部)

这里写图片描述

遇到这种bug最莫名其妙了,没有报出自己的代码错误它底层先崩溃,网上搜也没有搜到很明确的错误原因,而且看样子还是很频繁。尽管我解决的方法很简单,但也算是抛砖引玉,给大家排除异常时一个思路吧。根据异常信息,可以分出3种方向:

  • IndexOutOfBoundsException 数组越界异常
  • Inconsistency detected 发现了不一致
  • Invalid view holder 无效的Holder

自己写的代码数组越不越界应该很容易看得出来吧,(反正我这个绝对不是数组越界导致)排除!

然后着重看第二和第三个了,这两个似乎很少见,第三个我猜想应该是 RecyclerView 自己特有的异常判断,是它抛出来的 crash,那么第二个是什么东西…

发现了不一致,什么不一致,就想到了同步锁,因为 adapter 为了保持数据的一致性,在增加和删除数据可能同时操作的情况下,data 数据就必须保持一致性了。这样的猜想就很有可能了,然后看一下自己的代码

getItemViewTypeonBindViewHolder 这两个方法我也没做什么,就不列出来,我们只看重点,在 onCreateViewHolder 中根据类型判断使用哪种 holder ,很常规的添加不同布局的使用方法了,没什么问题

@Override
public InvoiceHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == NORMAL_ITEM) {
            return new InvoiceHolder(LayoutInflater.from(context).inflate(R.layout.item_invoice, parent, false));
        } else if (viewType == FOOTER_ITEM){
            return new InvoiceCommitHolder(LayoutInflater.from(context).inflate(R.layout.item_invoice_commit, parent, false));
        }
        return new InvoiceHolder(LayoutInflater.from(context).inflate(R.layout.item_invoice, parent, false));

}

接着是自己定义的方法添加底部,这段代码使用过程中也没有出现什么问题,如果已经有了footerView,就抛异常,没有就添加,运行也很正常,估计也没有问题的。

public void addFooterView(View view) {
        if (footerView != null) {
            throw new IllegalStateException("footerview has already exists!");
        } else {
            ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            view.setLayoutParams(params);
            footerView = view;
            notifyItemInserted(getItemCount() - 1);
        }
    }

//因为底部不算是data数据集的一个数据,固然在 getItemCount 就需要自己判断是否需要 +1
@Override
public int getItemCount() {
    int count = mData.size();
   if (footerView != null)
         count++;
    return count;
}

最后,移除底部布局

public void removeFooterView() {
    footerView = null;
    notifyDataSetChanged();
 // notifyItemInserted(getItemCount() - 1);
}

关键就是这里,是用 notifyDataSetChanged(正常) , 而不是用 notifyItemInserted(异常)
至于是为什么,我看源码解释说,当 item 被插入到新位置时通知任何注册了的观察者,item 以前在的位置是目前位置+ 1, 这是一个结构性变化的事件。表示数据集的其他现有的项目仍然被认为是最新的,不会反弹,尽管他们的位置可能会改变。也就是说数据集只更新了制定的那一项,其它不动,然后我让它指定更新的那一 item 却是 null ,所以就出现了问题。

个人水平有限,有问题可以大家探讨。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值