ankidroid / ankidroid/Anki-Android
Crash: IllegalStateException in BrowserColumnSelectionAdapter when toggling columns during drag-and-drop animation
- Lenguaje dominante
- Kotlin
- Estrellas
- 11.8k
- Forks
- 2.9k
- Merge medio
- 2 d 3 h
- PR fusionados (30 d)
- 167
Descripción
### Checked for duplicates?
- [x] This issue is not a duplicate
### Does it also happen in the desktop version?
- [ ] This bug does not occur in the latest version of Anki Desktop
### What are the steps to reproduce this bug?
### **Description**
A crash occurs in the Manage columns screen of the Card Browser. The crash is triggered when notifyItemRangeChanged is called within refreshDataset while the RecyclerView is still performing a layout pass or executing a recovery animation from ItemTouchHelper.
**### version**
Android Version: 9.0
Device: Google Medium Phone
App Version: 2.24.0alpha10-debug
### **Steps to Reproduce**
Open Card Browser.
Tap the overflow menu (three dots) and select Change display order (or long-press a header to enter Manage columns).
Perform the following actions rapidly:
Use the six-dot drag handle on the right to reorder any column (e.g., drag "Note Type" up or down).
Immediately after releasing the drag (while the animation is still finishing), tap the "+" or "—" button in the middle to add/remove a column.
The app crashes with java.lang.IllegalStateException.
**The crash is tested by automated testing tool, but I cannot reproduce by hand.**
### Expected behaviour
1.The app crashes with java.lang.IllegalStateException.
2.The app should handle the column toggle smoothly even if a drag-and-drop animation is active. Either the toggle action should wait for the animation to finish, or the UI should update without throwing an IllegalStateException. No crash should occur.
### Debug info
```text
Full Crash Log (Stacktrace)
> --------- beginning of crash
03-23 03:59:29.437 E/AndroidRuntime(22708): FATAL EXCEPTION: main
03-23 03:59:29.437 E/AndroidRuntime(22708): Process: com.ichi2.anki.debug, PID: 22708
03-23 03:59:29.437 E/AndroidRuntime(22708): java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling androidx.recyclerview.widget.RecyclerView{612e57c VFED..... ......ID 0,168-1080,2211 #7f0a0466 app:id/recycler_view}, adapter:com.ichi2.anki.browser.BrowserColumnSelectionAdapter@bfbde4, layout:androidx.recyclerview.widget.LinearLayoutManager@2c0e2, context:android.view.ContextThemeWrapper@41f1267
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:3587)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView$RecyclerViewDataObserver.onItemRangeChanged(RecyclerView.java:6167)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView$AdapterDataObservable.notifyItemRangeChanged(RecyclerView.java:13401)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView$AdapterDataObservable.notifyItemRangeChanged(RecyclerView.java:13391)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView$Adapter.notifyItemRangeChanged(RecyclerView.java:8259)
03-23 03:59:29.437 E/AndroidRuntime(22708): at com.ichi2.anki.browser.BrowserColumnSelectionAdapter.refreshDataset(BrowserColumnSelectionAdapter.kt:111)
03-23 03:59:29.437 E/AndroidRuntime(22708): at com.ichi2.anki.browser.BrowserColumnSelectionFragment$setupRecyclerView$callback$1.clearView(BrowserColumnSelectionFragment.kt:187)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.ItemTouchHelper$3.onAnimationEnd(ItemTouchHelper.java:652)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.animation.Animator$AnimatorListener.onAnimationEnd(Animator.java:552)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.animation.ValueAnimator.endAnimation(ValueAnimator.java:1232)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.animation.ValueAnimator.cancel(ValueAnimator.java:1117)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.ItemTouchHelper$RecoverAnimation.cancel(ItemTouchHelper.java:2446)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.ItemTouchHelper.endRecoverAnimation(ItemTouchHelper.java:929)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.ItemTouchHelper.onChildViewDetachedFromWindow(ItemTouchHelper.java:911)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView.dispatchChildDetached(RecyclerView.java:8473)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView$6.removeViewAt(RecyclerView.java:1005)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.ChildHelper.removeViewAt(ChildHelper.java:212)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView$LayoutManager.removeViewAt(RecyclerView.java:9585)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView$LayoutManager.removeAndRecycleViewAt(RecyclerView.java:9856)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.LinearLayoutManager.recycleChildren(LinearLayoutManager.java:1524)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.LinearLayoutManager.recycleViewsFromStart(LinearLayoutManager.java:1574)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.LinearLayoutManager.recycleByLayoutState(LinearLayoutManager.java:1649)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1708)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1485)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.LinearLayoutManager.scrollVerticallyBy(LinearLayoutManager.java:1218)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView.scrollStep(RecyclerView.java:2161)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView.scrollByInternal(RecyclerView.java:2260)
03-23 03:59:29.437 E/AndroidRuntime(22708): at androidx.recyclerview.widget.RecyclerView.onTouchEvent(RecyclerView.java:3958)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.view.View.dispatchTouchEvent(View.java:12513)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3024)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2705)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3030)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3030)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3030)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3030)
03-23 03:59:29.437 E/AndroidRuntime(22708): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2719)
03-23 03:59:29.438 E/AndroidRuntime(22708): at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:440)
03-23 03:59:29.438 E/AndroidRuntime(22708): at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1830)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.app.Dialog.dispatchTouchEvent(Dialog.java:847)
03-23 03:59:29.438 E/AndroidRuntime(22708): at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:398)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.View.dispatchPointerEvent(View.java:12752)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5106)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4909)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4426)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4479)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4445)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4585)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4453)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4642)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4426)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4479)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4445)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4453)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4426)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7092)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7061)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7022)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7195)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:186)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:177)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:7166)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:7218)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:949)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.Choreographer.doCallbacks(Choreographer.java:761)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.Choreographer.doFrame(Choreographer.java:690)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.os.Handler.handleCallback(Handler.java:873)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.os.Handler.dispatchMessage(Handler.java:99)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.os.Looper.loop(Looper.java:193)
03-23 03:59:29.438 E/AndroidRuntime(22708): at android.app.ActivityThread.main(ActivityThread.java:6669)
03-23 03:59:29.438 E/AndroidRuntime(22708): at java.lang.reflect.Method.invoke(Native Method)
03-23 03:59:29.438 E/AndroidRuntime(22708): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
03-23 03:59:29.438 E/AndroidRuntime(22708): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
03-23 03:59:29.712 I/ActivityManager( 1882): START u0 {flg=0x10000000 cmp=com.ichi2.anki.debug/com.ichi2.anki.analytics.AnkiDroidCrashReportDialog (has extras)} from uid 10098
03-23 03:59:30.052 I/chatty (23304): uid=10087(com.github.uiautomator) expire 3 lines
action before crash
> action: 8@click className=android.widget.TextView,instance=2 :android.widget.TextView@Sort Field
action: 9@click className=android.widget.TextView,instance=9 :android.widget.TextView@Card Modified
action: 15@clickLong className=android.widget.TextView,instance=5 :android.widget.TextView@Deck
action: 18@clickLong resource-id=com.ichi2.anki.debug:id/drag_handle :android.widget.ImageView@recycler items_com.ichi2.anki.CardBrowser_000001
action: 29@clickLong resource-id=com.ichi2.anki.debug:id/button_toggle_column :android.widget.ImageButton@recycler items_com.ichi2.anki.CardBrowser_000001
action: 27@clickLong className=android.widget.TextView,instance=9 :android.widget.TextView@recycler items_com.ichi2.anki.CardBrowser_000001
action: 3@back
action: 11@clickLong className=android.widget.TextView,instance=3 :android.widget.TextView@Note Type
action: 21@clickLong resource-id=com.ichi2.anki.debug:id/button_toggle_column :android.widget.ImageButton@recycler items_com.ichi2.anki.CardBrowser_000001
action: 24@click resource-id=com.ichi2.anki.debug:id/button_toggle_column :android.widget.ImageButton@recycler items_com.ichi2.anki.CardBrowser_000001
action: 35@clickLong className=android.widget.TextView,instance=11 :android.widget.TextView@recycler items_com.ichi2.anki.CardBrowser_000001
action: 9@clickLong resource-id=com.ichi2.anki.debug:id/button_toggle_column :android.widget.ImageButton@recycler items_com.ichi2.anki.CardBrowser_000001
action: 19@clickLong className=android.widget.TextView,instance=7 :android.widget.TextView@recycler items_com.ichi2.anki.CardBrowser_000001
--------- beginning of crash
03-23 03:59:29.437 22708 22708 E AndroidRuntime: FATAL EXCEPTION: main
03-23 03:59:29.437 22708 22708 E AndroidRuntime: Process: com.ichi2.anki.debug, PID: 22708
```
### (Optional) Anything else you want to share?
_No response_
### Research
- [x] I have checked the [manual](https://ankidroid.org/docs/manual.html) and the [FAQ](https://github.com/ankidroid/Anki-Android/wiki/FAQ) and could not find a solution to my issue
- [ ] (Optional) I have confirmed the issue is not resolved in the latest alpha release ([instructions](https://docs.ankidroid.org/manual.html#betaTesting))
Guía de contribución
Evaluación
Este issue todavía no se ha evaluado.