RecyclerView異常之:IllegalStateException

一. assertNotInLayoutOrScroll引起的IllegalStateException

通過(guò)調(diào)用 notifyxxx 對(duì)適配器進(jìn)行更新時(shí),會(huì)調(diào)用到RecyclerView的assertNotInLayoutOrScroll,該方法可能會(huì)拋出IllegalStateException

異常拋出點(diǎn):

void assertNotInLayoutOrScroll(String message) {
        if (this.isComputingLayout()) {
            if (message == null) {
                throw new IllegalStateException("Cannot call this method while RecyclerView is computing a layout or scrolling" + this.exceptionLabel());
            } else {
                throw new IllegalStateException(message);
            }
        } else {
            if (this.mDispatchScrollCounter > 0) {
                Log.w("RecyclerView", "Cannot call this method in a scroll callback. Scroll callbacks mightbe run during a measure & layout pass where you cannot change theRecyclerView data. Any method call that might change the structureof the RecyclerView or the adapter contents should be postponed tothe next frame.", new IllegalStateException("" + this.exceptionLabel()));
            }

        }
    }
問(wèn)題:
1. Cannot call this method while RecyclerView is computing a layout or scrolling
   該問(wèn)題直接原因是RecyclerView的isComputingLayout()為true導(dǎo)致。
   字面意思就是不要在RecyclerView正在layout的時(shí)候,去嘗試更新適配器內(nèi)容。

解決方法:

 public final void notifyDataSetChangedSafely() {
        if (mRecyclerView != null && mRecyclerView.isComputingLayout()) {
            mRecyclerView.post(new Runnable() {
                @Override
                public void run() {
                    notifyDataSetChanged();
                }
            });
        } else {
            notifyDataSetChanged();
        }
    }

即在調(diào)用notifyDataSetChanged等方法時(shí),判斷RecyclerView是否在ComputingLayout,如果是的話,在下一條消息中notifyDataSetChanged等方法。

2. Cannot call this method in a scroll callback
   該問(wèn)題直接原因是RecyclerView的mDispatchScrollCounter>0導(dǎo)致。
   字面意思就是不要在RecyclerView執(zhí)行Scroll動(dòng)作的回調(diào)方法的時(shí)候去嘗試直接更新適配器內(nèi)容。

其值變化所在位置:

void dispatchOnScrolled(int hresult, int vresult) {
        ++this.mDispatchScrollCounter;
        int scrollX = this.getScrollX();
        int scrollY = this.getScrollY();
        this.onScrollChanged(scrollX, scrollY, scrollX, scrollY);
        this.onScrolled(hresult, vresult);
        if (this.mScrollListener != null) {
            this.mScrollListener.onScrolled(this, hresult, vresult);
        }

        if (this.mScrollListeners != null) {
            for(int i = this.mScrollListeners.size() - 1; i >= 0; --i) {
                ((RecyclerView.OnScrollListener)this.mScrollListeners.get(i)).onScrolled(this, hresult, vresult);
            }
        }

        --this.mDispatchScrollCounter;
    }

代碼一目了然,即不要在RecyclerView回調(diào)onScrollChanged,onScrolled的時(shí)候去嘗試直接更新適配器內(nèi)容,
也不要在RecyclerView的OnScrollListener回調(diào)onScrolled的時(shí)候去嘗試直接更新適配器內(nèi)容。

比如我們通常會(huì)在RecyclerView滑動(dòng)到底部的時(shí)候去加載更多數(shù)據(jù)來(lái)填充列表:

 recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(final RecyclerView recyclerView, int dx, int dy) {
                  if (isLastViewMoreView(recyclerView)) {
                      onLoadMore();
                  }
            }
        });

分兩種情況:
a. 我們的onLoadMore的數(shù)據(jù)來(lái)源是網(wǎng)絡(luò),因?yàn)榫W(wǎng)絡(luò)請(qǐng)求是異步返回,就不會(huì)出現(xiàn)問(wèn)題。
b. 我們的onLoadMore的數(shù)據(jù)來(lái)源是本地,即請(qǐng)求可能是同步返回,這個(gè)時(shí)候如果直接更新適配器,那么這個(gè)更新動(dòng)作就是在onScrolled方法的執(zhí)行序列中進(jìn)行了,這就會(huì)導(dǎo)致call this method in a scroll callback

解決方法:

recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(final RecyclerView recyclerView, int dx, int dy) {
                if (isLastViewMoreView(recyclerView)) {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            onLoadMore();
                        }
                    });
                }
            }
        });

即在調(diào)用onScrolled方法時(shí),在下一條消息中去調(diào)用onLoadMore方法(更新適配器動(dòng)作在onScrolled等方法的執(zhí)行序列中的方法)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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