RecyclerView Inconsistency detected. Invalid item position異常原因及解決方案

  • 引起異常的原因

java.lang.IndexOutOfBoundsException : Inconsistency detected. Invalid item position異常
字面意思即檢測到不一致數據,一般情況下都是因為修改了適配器adapter的數據源而沒有即時調用相應的notify方法造成的。比如有一個adapter的數據源是通過讀取一個list來獲取的,如果在某個地方調用了List.clear()方法清空數據,但這時沒有即時調用notifyItemRangeRemoved()方法,之后又為了添加一些數據而調用了List.add()方法,而這時再在之后直接調用其他的notify方法,就會拋出該異常。這個異常比較坑爹的地方在于出現這種問題時只會在RecyclerView內部拋出異常,通俗的說,就是拋出的一大推異常中不會出現熟悉的“Cause by”告訴你在自己寫的代碼的那個地方拋出了異常,這個時候我們往往是懵逼的。下面是我實際應用場景中遇到的情況

1 android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5011)
2 android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4967)
3 android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2029)
4 android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1414)
5 android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1377)
6 android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:578)
7 android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3315)
8 android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3124)
9 android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3568)
10 android.view.View.layout(View.java:16754)
11 android.view.ViewGroup.layout(ViewGroup.java:5462)
12 android.widget.LinearLayout.setChildFrame(LinearLayout.java:1764)
13 android.widget.LinearLayout.layoutVertical(LinearLayout.java:1607)
14 android.widget.LinearLayout.onLayout(LinearLayout.java:1516)
15 android.view.View.layout(View.java:16754)
16 android.view.ViewGroup.layout(ViewGroup.java:5462)
17 android.widget.FrameLayout.layoutChildren(FrameLayout.java:338)
18 android.widget.FrameLayout.onLayout(FrameLayout.java:273)
19 android.view.View.layout(View.java:16754)
20 android.view.ViewGroup.layout(ViewGroup.java:5462)
21 android.widget.LinearLayout.setChildFrame(LinearLayout.java:1764)
22 android.widget.LinearLayout.layoutVertical(LinearLayout.java:1607)
23 android.widget.LinearLayout.onLayout(LinearLayout.java:1516)
24 android.view.View.layout(View.java:16754)
25 android.view.ViewGroup.layout(ViewGroup.java:5462)
26 android.widget.FrameLayout.layoutChildren(FrameLayout.java:338)
27 android.widget.FrameLayout.onLayout(FrameLayout.java:273)
28 android.view.View.layout(View.java:16754)
29 android.view.ViewGroup.layout(ViewGroup.java:5462)
30 android.widget.LinearLayout.setChildFrame(LinearLayout.java:1764)
31 android.widget.LinearLayout.layoutVertical(LinearLayout.java:1607)
32 android.widget.LinearLayout.onLayout(LinearLayout.java:1516)
33 android.view.View.layout(View.java:16754)
34 android.view.ViewGroup.layout(ViewGroup.java:5462)
35 android.widget.FrameLayout.layoutChildren(FrameLayout.java:338)
36 android.widget.FrameLayout.onLayout(FrameLayout.java:273)
37 com.android.internal.policy.PhoneWindow$DecorView.onLayout(PhoneWindow.java:2748)
38 android.view.View.layout(View.java:16754)
39 android.view.ViewGroup.layout(ViewGroup.java:5462)
40 android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2226)
41 android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1983)
42 android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1139)
43 android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6238)
44 android.view.Choreographer$CallbackRecord.run(Choreographer.java:884)
45 android.view.Choreographer.doCallbacks(Choreographer.java:696)
46 android.view.Choreographer.doFrame(Choreographer.java:631)
47 android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:870)
48 android.os.Handler.handleCallback(Handler.java:743)
49 android.os.Handler.dispatchMessage(Handler.java:95)
50 android.os.Looper.loop(Looper.java:150)
51 android.app.ActivityThread.main(ActivityThread.java:5546)
52 java.lang.reflect.Method.invoke(Native Method)
53 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794)
54 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:684)

通常遇到這種情況直接是連看的欲望都沒有的。

  • 解決方案

廢話不多說,主要的解決思路還是之前說的,這是由于數據不同步造成的。

  1. 首先需要找到拋出異常的地方
    由于無法從拋出的異常中知道代碼的邏輯在那出錯,只能照之前說的先找到自己代碼中對數據源進行過修改的地方,檢查是否在數據源修改過之后調用了相應的notify方法。這里我是通過log輸出標記定位到了出錯的代碼塊。原因在于我使用RXJava時,數據源變化和adapter的notify方法調用不在用一個線程造成的。
//注:messageList為適配器顯示的item實例list
Observable.create(new Observable.OnSubscribe<String>() {
                        @Override
                        public void call(Subscriber<? super String> subscriber) {
                            ...
                            messageList.clear();
                            ...
                            subscriber.onNext("");
                        }
                    }).subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe(new Subscriber<String>() {
                                @Override
                                public void onCompleted() {
                                }

                                @Override
                                public void onError(Throwable e) {
                                }

                                @Override
                                public void onNext(String s) {
                                    ...
                                    msgAdapter.notifyItemRangeRemoved(0, itemCount);
                                    ...
                                }
                            });
  1. 問題原因
    這里簡單說一下代碼邏輯,就是在IO線程中執耗時行業務邏輯,調用了list的clear()方法,而之后在UI線程中才調用了notifyItemRangeRemoved()方法。這里看似沒有問題,但是因為list的clear()方法調用是異步的,這意味著list這時可能不僅僅執行了clear()方法,還可能執行了其他操作,而之后再來執行notifyItemRangeRemoved()方法就產生了這個異常,因為當你通知適配器有多個數據插入時,這時的list的實際數據很可能已經不再與這個邏輯處理后的list匹配了。
  2. 解決辦法
    這里將數據源操作與適配器操作寫在同一線程中,保證list調用clear()方法后立即執行notifyItemRangeRemoved()就解決問題了。
@Override
 public void onNext(String s) {
 ...
  int itemCount = messageList.size();
  messageList.clear();
   msgAdapter.notifyItemRangeRemoved(0, itemCount);
    ...
   }
  • 問題總結

其實這個問題解決起來很簡單,就是保證數據源和適配器修改后保持數據一致就行。但是往往很多時候我們并沒有意識到自己違背了這一原則,尤其是在引入多線程之后。
另外,使用recyclerView的時候,進行數據刷新的時候作盡量不要直接使用notifyDataChanged(),而是使用相應的局部刷新方法。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,808評論 25 708
  • afinalAfinal是一個android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,487評論 2 45
  • 以下是具體的錯誤類型:原因是因為依賴的support包的版本不一致,包括依賴的module中的jar。解決辦法是保...
    相木目閱讀 1,036評論 0 0
  • 感謝各位老師的無私分享,通過這些天老師的分享,讓我學到了非常多! 第一 瘦瘦包的專業知識 第二 如何發朋友圈 第三...
    yomiko純中藥外敷減肥閱讀 209評論 0 0
  • 這是我離開的前一天晚上所畫,我以為我會成長為你身邊的木棉樹,不曾想我對你來說只是一顆開花的樹。
    汪穩_fed5閱讀 208評論 0 0