那些年踩過的坑

RecyclerView的IndexOutOfBoundsException異常

大半年沒有敲代碼了,順手寫個上拉加載更多居然就出現(xiàn)了異常,還是系統(tǒng)異常,讓人費解.
異常信息:

崩潰了 : 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)

在網(wǎng)上查閱資料,處理方式主要分為兩種.

  1. 繼承LinearLayoutManager,重寫onLayoutChildren

可以說這種辦法單純?yōu)榱薱atch住異常,問題只是被掩蓋,并沒有解決問題,當鴕鳥并不能解決問題.

  1. 更新完數(shù)據(jù)及時調(diào)用notifyxxx相關(guān)方法,通知數(shù)據(jù)更新

這種是正常做法,我也是用的這種,但是在Adapter的集合對象修改了之后調(diào)用還是容易出現(xiàn)異常.

問題所在

google的官方回復(fù)也是說在數(shù)據(jù)變化之后及時調(diào)用notify更新,我前面出現(xiàn)了一個認知上的錯誤.
Adapter的數(shù)據(jù)對象通常用List進行封裝,我只在List對象有變化的時候調(diào)用notify更新數(shù)據(jù).
對于RecyclerView來說數(shù)據(jù)變化并不在于我封裝的List,而是getItemCount()的返回值,我的問題就出現(xiàn)在List集合對象沒有改變的時候卻改變了getItemCount()的值.

RecyclerView中數(shù)據(jù)長度并不是通過實時調(diào)用getItemCount()來確定.而是通過RecyclerView.State對象中的mItemCount對象來確定數(shù)據(jù)長度,在調(diào)用notify方法時會調(diào)用requestLayout()方法來進行重新測量,繪制,并對mItemCount進行重新賦值.

拋出異常的代碼:

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

這里也可以清楚地看出拋出異常的條件,holder的數(shù)量由mItemCount來進行控制,當更新完數(shù)據(jù)之后再更改了mAdapter.getItemCount()的返回值,一旦將返回值變小就會觸發(fā)異常,并拋出.

我的異常

我簡單的隨便寫了個上拉加載更多,根據(jù)是否需要加載更多來判斷來決定是否增加加載更多的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 新版本優(yōu)化之后內(nèi)部維護了長度mItemCount,并不是每次調(diào)用 getItemCount. 所以需要保證返回結(jié)果不變,或者結(jié)果改變之后調(diào)用更新數(shù)據(jù)
        }
    }

我的解決

在getItemCount()值需要調(diào)用notify方法同步的情況下,通過mLoadMore來變更返回值就需要多調(diào)用幾次notify方法了,為了避免不必要的刷新,最終解決方式通過判斷mLoadMore的值直接顯示或隱藏加載更多的holder.
一個多調(diào)用一次刷新,一個多調(diào)用一次Holder的創(chuàng)建綁定的那個流程,也不好判斷那種方式更優(yōu).
但是隱藏方式需要注意若addItemDecoration()需要注意隱藏了一個,也要對itemDecoration進行處理,不然會出現(xiàn)兩條重合,影響界面.

成員對象初始化問題

一直以來就認為成員變量直接初始化隨時都能用,然后就被坑了一把.

問題情況

B類有個成員變量,直接實例化的成員變量

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

該對象在構(gòu)造方法調(diào)用的過程中傳遞給對象C.結(jié)果對象B中mList初始化成功,C對象中為Null.

問題原因

B類繼承了A類,B類的初始化是直接使用的A類構(gòu)造函數(shù)中調(diào)用的抽象的init()方法.
在初始化時先調(diào)用父類構(gòu)造函數(shù),父類構(gòu)造函數(shù)中調(diào)用子類init實例化方法,然而此時父類構(gòu)造方法還沒走完,子類成員變量還未進行初始化過程,從而導致類傳遞給C類的對象為null.

解決方式

  1. 父類不調(diào)用初始化方法,父類構(gòu)造函數(shù)中就不該調(diào)用子類方法,因為父類調(diào)用時子類方法時,子類成員變量都還未進行初始化,很容易出現(xiàn)各種問題.
  2. 子類不在聲明時初始化,在init()方法中進行成員變量的初始化.
  3. 父類不調(diào)用初始化方法,子類在構(gòu)造函數(shù)中自行調(diào)用初始化方法.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Fragment系列文章:1、Fragment全解析系列(一):那些年踩過的坑2、Fragment全解析系列(二)...
    YoKey閱讀 239,458評論 164 1,233
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,854評論 18 399
  • 1.使用databinding時,在布局文件中設(shè)置android:onclick屬性,在viewmodel文件中處...
    7397aef58145閱讀 168評論 0 0
  • 2016-07-27 使用nginx中轉(zhuǎn)時,如后端服務(wù)時間過長,導致前段頁面返回http的504 gateway ...
    黃言黃語閱讀 903評論 0 0
  • 兩個生命同時在窮苦小鎮(zhèn)的一條幽避的胡同里降生了,一個男孩,一個女孩?;蛟S是因為緣份。更或許是因為聽信了算命先生說要...
    羽萌520閱讀 257評論 0 0

友情鏈接更多精彩內(nèi)容