Android erroe:RecyclerViewがレイアウトを計算している間、またはスクロールしている間は、このメソッドを呼び出すことはできません



Android Erroe Cannot Call This Method While Recyclerview Is Computing Layout



私は今日のプロジェクトでこの問題に遭遇し、将来の忘却を防ぐためにこの場合にそれを記録しました。ちなみに、ハンドラーメカニズムがリコールされています。

まず、最初の解決策



データの更新操作は、ハンドラーを使用して実行されます。

// You need to make sure that the Looper of this Handler is the Looper of the main thread. // That is, if the following code block is executed in the main thread, ignore it. // If not, you need Handler handler = new Handler(Looper.getMainLooper()) Handler handler = new Handler() handler.post(new Runnable() { @Override public void run() { notifyDataSetChanged() } })

第二に、なぜこのクラッシュなのですか?



CRASHの文字通りの側面から、これはRecyclerViewレイアウトまたはスクロールプロセスでnotifyDataSetChangedメソッドを呼び出すことによって発生します。
プロジェクトの特定の動作は次のとおりです。左または右のスライドがアイテムを削除すると、notifyDataSetChangedが呼び出されてデータソースが更新されます。

特定のクラッシュを見てください

06-27 16:49:50.463 E/AndroidRuntime(20889): FATAL EXCEPTION: main 06-27 16:49:50.463 E/AndroidRuntime(20889): Process: a, PID: 20889 06-27 16:49:50.463 E/AndroidRuntime(20889): java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:2349) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onChanged(RecyclerView.java:4551) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:10366) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:6044) 06-27 16:49:50.463 E/AndroidRuntime(20889): at a.gui.adapters.TrackAdapters.QueueTrackAdapter$TrackViewHolder.onItemClear(QueueTrackAdapter.java:522) 06-27 16:49:50.463 E/AndroidRuntime(20889): at a.gui.adapters.swipedrag.SimpleItemTouchHelperCallback.clearView(SimpleItemTouchHelperCallback.java:124) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.helper.ItemTouchHelper.onChildViewDetachedFromWindow(ItemTouchHelper.java:876) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView.dispatchChildDetached(RecyclerView.java:6234) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView.access$1200(RecyclerView.java:151) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView$5.removeViewAt(RecyclerView.java:651) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.ChildHelper.removeViewAt(ChildHelper.java:168) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView$LayoutManager.removeViewAt(RecyclerView.java:7092) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView$LayoutManager.scrapOrRecycleView(RecyclerView.java:7638) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView$LayoutManager.detachAndScrapAttachedViews(RecyclerView.java:7624) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:546) 06-27 16:49:50.463 E/AndroidRuntime(20889): at a.gui.activities.QueueActivity$WrapContentLinearLayoutManager.onLayoutChildren(QueueActivity.java:359) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3260) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3069) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1478) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView.scrollByInternal(RecyclerView.java:1542) 06-27 16:49:50.463 E/AndroidRuntime(20889): at android.support.v7.widget.RecyclerView.onTouchEvent(RecyclerView.java:2649) ...... ...... 06-27 16:49:50.464 E/AndroidRuntime(20889): at android.os.Handler.handleCallback(Handler.java:836) 06-27 16:49:50.464 E/AndroidRuntime(20889): at android.os.Handler.dispatchMessage(Handler.java:103) 06-27 16:49:50.464 E/AndroidRuntime(20889): at android.os.Looper.loop(Looper.java:203) 06-27 16:49:50.464 E/AndroidRuntime(20889): at android.app.ActivityThread.main(ActivityThread.java:6347) 06-27 16:49:50.464 E/AndroidRuntime(20889): at java.lang.reflect.Method.invoke(Native Method) 06-27 16:49:50.464 E/AndroidRuntime(20889): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063) 06-27 16:49:50.464 E/AndroidRuntime(20889): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)

RecyclerViewでは、RecyclerViewのアダプタがデータを更新すると、フローに従ってassertNotInLayoutOrScroll()のメソッドが実行されます。
assertNotInLayoutOrScroll()このメソッドは、メソッド名から確認して、レイイングかスクロールかを検出できます。



void assertInLayoutOrScroll(String message) { if (!isComputingLayout()) { if (message == null) { throw new IllegalStateException('Cannot call this method unless RecyclerView is ' + 'computing a layout or scrolling') } throw new IllegalStateException(message) } }

その中で、それはisComputingLayout()によって判断されます

public boolean isComputingLayout() { return mLayoutOrScrollCounter > 0 }

mLayoutOrScrollCounter変数またはフラグは、mLayoutOrScrollCounterの描画の開始時にmLayoutOrScrollCounter ++になります-

ログから、私のメソッドonItemClear()は描画プロセス中です。つまり、現時点ではmLayoutOrScrollCounterはゼロ以外です。したがって、onItemClear()でnotifyDataSetChanged()を直接呼び出すとクラッシュします。

第三に、なぜハンドラー処理を使用するのですか?

Androidのメッセージメカニズムを理解している学生は、AndroidのUIの更新が実際にはメッセージメカニズムによって実現されることを知っておく必要があります。メッセージを通して
さまざまな処理のために配布されます。

ログの最後の数行からも確認できます。

...... 06-27 16:49:50.464 E/AndroidRuntime(20889): at android.os.Handler.handleCallback(Handler.java:836) 06-27 16:49:50.464 E/AndroidRuntime(20889): at android.os.Handler.dispatchMessage(Handler.java:103) 06-27 16:49:50.464 E/AndroidRuntime(20889): at android.os.Looper.loop(Looper.java:203) ......

Handler.postメソッドを使用して、RunnableメソッドブロックをMessageQueueに入れ(先入れ先出し、先入れ先出し)、実行を待機します。メインスレッドのルーパーは、このキュー内のメッセージをループします。一般に、このプロセスはシリアルです。したがって、Handle.postを使用する場合、UI更新メッセージが最初にダイジェストされます。ルーパーがメッセージキューからポストメッセージを取り出すと、[データソースの更新]操作が実行されます。

ただし、この時点でRecyclerViewの描画は完了しており、mLayoutOrScrollCounterは0に設定されているため、データソースを正常に更新できます。

順番: https://www.jianshu.com/p/353d401fbd99