關(guān)于RecyclerView數(shù)據(jù)刷新的問題

在使用RecyclerView進(jìn)行數(shù)據(jù)移除或者增加的時候,有時候會出現(xiàn)以下這個異常:

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{431a7450 position=1 id=-1, oldPos=-1, pLpos:-1 scrap [attachedScrap] tmpDetached no parent}  
    at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:4251)  
    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4382)  
    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4363)  
    at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1961)  
    at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1370)  
    at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1333)  
    at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:562)  
    at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:2900)  
    at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3071)  

那么,這個異常是如何產(chǎn)生的,怎么解決呢?

在RecyclerView中废岂,有四種方式刷新數(shù)據(jù):
1.notifyDataSetChanged();這個是ListView的使用方法漂辐,在RecyclerView中同樣適用泪喊,但是這個不是官方推薦的,因?yàn)镽ecyclerView相對于ListView提供了局部刷新接口髓涯,而且局部刷新有動畫效果袒啼。
2.notifyItemRangeRemoved();
3.notifyItemRangeInserted()纬纪;
4.notifyItemRangeChanged()蚓再;

刷新數(shù)據(jù)的后三種方法推薦使用,但是使用不好會出現(xiàn)剛才文章開始的異常包各;下面分析這個異常產(chǎn)生的原因摘仅。

下面看看以前個人開發(fā)是遇到的一個此類問題:

/**
     * 插入新數(shù)據(jù)
     */
    public void insertData(List<T> insertedData) {
        if (insertedData == null) {
            Log.e(TAG, "insertData(list) list is null");
            return;
        }
        for (T data : insertedData){
            if (data!=null){
                mDatas.add(data);
            }
        }
        notifyItemRangeInserted(mDatas.size() - insertedData.size(), insertedData.size());
    }

以上代碼中,當(dāng)insertData中有空數(shù)據(jù)的時候就會出現(xiàn)異常问畅,如果有空數(shù)據(jù)娃属,后面notifyItemRangeInserted中的起始位置和增加的item數(shù)量就和mDatas中的不一致,mDatas我們成為adapter內(nèi)部數(shù)據(jù)护姆,insertData成為外部數(shù)據(jù)矾端,我們應(yīng)該實(shí)時保持?jǐn)?shù)據(jù)的一致性。

修改后的代碼為:
/**
     * 插入新數(shù)據(jù)
     */
    public void insertData(List<T> insertedData) {
        if (insertedData == null) {
            Log.e(TAG, "insertData(list) list is null");
            return;
        }
        int index = 0;
        for (T data : insertedData) {
            if (data != null) {
                mDatas.add(data);
                index++;
            }
        }
        notifyItemRangeInserted(mDatas.size() - index, index);
    }

還有一個問題卵皂,對RecyclerView數(shù)據(jù)的刷新操作要分解為“原子”操作秩铆,“原子”操作就三個,移除灯变,增加殴玛,修改。舉個例子說明一下:

public void notifyData(List<PoiItem> poiItemList) {
    if (poiItemList != null ) {
        mPoiItems.clear();
        mPoiItems.addAll(poiItemList);
        notifyItemRangeChanged(0, poiItemList.size());
    }
}

在上面的操作中添祸,首先是移除了數(shù)據(jù)滚粟,但是沒有刷新RecyclerView,然后又增加了數(shù)據(jù)刃泌,這時候刷新了RecyclerView坦刀,這個時候就會出問題愧沟,所有把這個過程拆為兩步:

public void notifyData(List<PoiItem> poiItemList) {
    if (poiItemList != null) {
        int previousSize = mPoiItems.size();
        mPoiItems.clear();
        notifyItemRangeRemoved(0, previousSize);
        mPoiItems.addAll(poiItemList);
        notifyItemRangeInserted(0, poiItemList.size());
    }
}

所以總結(jié)一下為:如果使用RecyclerView的局部刷新功能蔬咬,每次adapter的內(nèi)部數(shù)據(jù)集發(fā)生改變時鲤遥,都要主動調(diào)用一下數(shù)據(jù)刷新,以保持?jǐn)?shù)據(jù)的一致性林艘。

參考文章:
http://www.reibang.com/p/2eca433869e9

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末盖奈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子狐援,更是在濱河造成了極大的恐慌钢坦,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啥酱,死亡現(xiàn)場離奇詭異爹凹,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)镶殷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門禾酱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人绘趋,你說我怎么就攤上這事颤陶。” “怎么了陷遮?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵滓走,是天一觀的道長。 經(jīng)常有香客問我帽馋,道長搅方,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任绽族,我火速辦了婚禮姨涡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘项秉。我一直安慰自己绣溜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布娄蔼。 她就那樣靜靜地躺著怖喻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪岁诉。 梳的紋絲不亂的頭發(fā)上锚沸,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機(jī)與錄音涕癣,去河邊找鬼哗蜈。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的距潘。 我是一名探鬼主播炼列,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼音比!你這毒婦竟也來了俭尖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤洞翩,失蹤者是張志新(化名)和其女友劉穎稽犁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骚亿,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡已亥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了来屠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虑椎。...
    茶點(diǎn)故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖的妖,靈堂內(nèi)的尸體忽然破棺而出绣檬,到底是詐尸還是另有隱情,我是刑警寧澤嫂粟,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布娇未,位于F島的核電站,受9級特大地震影響星虹,放射性物質(zhì)發(fā)生泄漏零抬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一宽涌、第九天 我趴在偏房一處隱蔽的房頂上張望平夜。 院中可真熱鬧,春花似錦卸亮、人聲如沸忽妒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽段直。三九已至,卻和暖如春溶诞,著一層夾襖步出監(jiān)牢的瞬間鸯檬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工螺垢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留喧务,地道東北人赖歌。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像功茴,于是被迫代替她去往敵國和親庐冯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容