那些年踩过的坑

RecyclerView的IndexOutOfBoundsException异常

大半年没有敲代码了,顺手写个上拉加载更多居然就出现了异常,还是系统异常,让人费解.
异常信息:

崩溃了 : java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{3b3cebd position=5 id=-1, oldPos=-1, pLpos:-1 no parent}
    at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5297)
    at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5479)
    at android.support.v7.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:282)
    at android.support.v7.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:336)
    at android.support.v7.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:349)
    at android.support.v7.widget.GapWorker.prefetch(GapWorker.java:356)
    at android.support.v7.widget.GapWorker.run(GapWorker.java:387)
    at android.os.Handler.handleCallback(Handler.java:761)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:156)
    at android.app.ActivityThread.main(ActivityThread.java:6523)

10-19 10:08:38.892 17210-17210/? E/My custom tag: │     at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)

在网上查阅资料,处理方式主要分为两种.

  1. 继承LinearLayoutManager,重写onLayoutChildren

可以说这种办法单纯为了catch住异常,问题只是被掩盖,并没有解决问题,当鸵鸟并不能解决问题.

  1. 更新完数据及时调用notifyxxx相关方法,通知数据更新

这种是正常做法,我也是用的这种,但是在Adapter的集合对象修改了之后调用还是容易出现异常.

问题所在

google的官方回复也是说在数据变化之后及时调用notify更新,我前面出现了一个认知上的错误.
Adapter的数据对象通常用List进行封装,我只在List对象有变化的时候调用notify更新数据.
对于RecyclerView来说数据变化并不在于我封装的List,而是getItemCount()的返回值,我的问题就出现在List集合对象没有改变的时候却改变了getItemCount()的值.

RecyclerView中数据长度并不是通过实时调用getItemCount()来确定.而是通过RecyclerView.State对象中的mItemCount对象来确定数据长度,在调用notify方法时会调用requestLayout()方法来进行重新测量,绘制,并对mItemCount进行重新赋值.

抛出异常的代码:

            if (holder.mPosition < 0 || holder.mPosition >= mAdapter.getItemCount()) {
                throw new IndexOutOfBoundsException("Inconsistency detected. Invalid view holder "
                        + "adapter position" + holder);
            }

这里也可以清楚地看出抛出异常的条件,holder的数量由mItemCount来进行控制,当更新完数据之后再更改了mAdapter.getItemCount()的返回值,一旦将返回值变小就会触发异常,并抛出.

我的异常

我简单的随便写了个上拉加载更多,根据是否需要加载更多来判断来决定是否增加加载更多的holder界面

    @Override
    public int getItemCount() {
        if (mList == null || mList.size() == 0) {
            return 0;
        } else {
            return mLoadMore ? mList.size() + 1 : mList.size();
            // TODO: 2017.10.16 google 新版本优化之后内部维护了长度mItemCount,并不是每次调用 getItemCount. 所以需要保证返回结果不变,或者结果改变之后调用更新数据
        }
    }

我的解决

在getItemCount()值需要调用notify方法同步的情况下,通过mLoadMore来变更返回值就需要多调用几次notify方法了,为了避免不必要的刷新,最终解决方式通过判断mLoadMore的值直接显示或隐藏加载更多的holder.
一个多调用一次刷新,一个多调用一次Holder的创建绑定的那个流程,也不好判断那种方式更优.
但是隐藏方式需要注意若addItemDecoration()需要注意隐藏了一个,也要对itemDecoration进行处理,不然会出现两条重合,影响界面.

成员对象初始化问题

一直以来就认为成员变量直接初始化随时都能用,然后就被坑了一把.

问题情况

B类有个成员变量,直接实例化的成员变量

    private List<Object> mList = new ArrayList<>();

该对象在构造方法调用的过程中传递给对象C.结果对象B中mList初始化成功,C对象中为Null.

问题原因

B类继承了A类,B类的初始化是直接使用的A类构造函数中调用的抽象的init()方法.
在初始化时先调用父类构造函数,父类构造函数中调用子类init实例化方法,然而此时父类构造方法还没走完,子类成员变量还未进行初始化过程,从而导致类传递给C类的对象为null.

解决方式

  1. 父类不调用初始化方法,父类构造函数中就不该调用子类方法,因为父类调用时子类方法时,子类成员变量都还未进行初始化,很容易出现各种问题.
  2. 子类不在声明时初始化,在init()方法中进行成员变量的初始化.
  3. 父类不调用初始化方法,子类在构造函数中自行调用初始化方法.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • Fragment系列文章:1、Fragment全解析系列(一):那些年踩过的坑2、Fragment全解析系列(二)...
    YoKey阅读 237,659评论 163 1,234
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,577评论 18 399
  • 1.使用databinding时,在布局文件中设置android:onclick属性,在viewmodel文件中处...
    7397aef58145阅读 141评论 0 0
  • 2016-07-27 使用nginx中转时,如后端服务时间过长,导致前段页面返回http的504 gateway ...
    黄言黄语阅读 855评论 0 0
  • 两个生命同时在穷苦小镇的一条幽避的胡同里降生了,一个男孩,一个女孩。或许是因为缘份。更或许是因为听信了算命先生说要...
    羽萌520阅读 204评论 0 0