AppFlowy-IO / AppFlowy-IO/appflowy-editor

Mobile selection auto-scroll can enter feedback loop / ANR when table focus changes

Offen
#1,215 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Dart
Sterne
684
Forks
329
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

### Description

After fixing the table row-height relayout loop from #1213 / #1214, the same mobile table interaction still exposed a second, independent hang in editor auto-scroll.

On a physical Android device, editing a table cell, tapping out of it, then tapping back into the table could ANR the app. With the microtask starvation fixed, the remaining symptom appeared as the page content/table rapidly vibrating until tapping out again, which indicates a repeat auto-scroll feedback loop.

This did not reproduce on the Pixel emulator or Chrome in my testing; it reproduced on a physical Galaxy S23+.

### Environment

- AppFlowy Editor: 6.1.0 / 6.2.0 code path
- Flutter: 3.41.2 stable
- Device: Galaxy S23+ (SM-S916U)
- OS: Android 16
- Renderer: Impeller / Vulkan
- Scenario: mobile editor, table cell focus/defocus, selection/caret update near table content

### Root cause

There are two related problems in the mobile auto-scroll path:

1. The vendored `EdgeDraggingAutoScroller._scroll` in `lib/src/flutter/scrollable_helpers.dart` recursively awaits itself:

```dart
if (_scrolling) {
await _scroll();
}
```

`ScrollPosition.moveTo` can complete synchronously, especially when the scroll position cannot make meaningful progress. In that case, the async recursion can become a tight microtask chain and starve frames/input.

2. Mobile selection changes call `startAutoScroll` even for ordinary caret/table focus updates. Those should be one-shot keep-visible nudges, not repeating auto-scroll. Otherwise, after moving repeat work to frame callbacks, the bug remains visible as rapid content vibration.

### Symbolicated ANR stack

A release APK built with split debug info produced this main-thread Dart stack shape:

```text
ChangeNotifier.notifyListeners
-> _RestorableScrollOffset.didUpdateValue
-> ScrollableState.saveOffset
-> ScrollPosition.didEndScroll
-> ScrollPositionWithSingleContext.jumpTo
-> ViewportOffset.moveTo
-> ScrollPosition.moveTo
-> EdgeDraggingAutoScroller._scroll
-> EdgeDraggingAutoScroller._scroll
-> _microtaskLoop
```

### Expected behavior

Table focus/defocus and caret movement should settle. Auto-scroll should repeat only during actual drag selection and should yield between ticks so frames/input can continue.

### Actual behavior

The editor can enter an auto-scroll feedback loop. On the physical Android device this manifested first as an ANR, and after partial mitigation as visible table/content vibration until tapping out.

### Proposed fix

- Schedule repeated auto-scroll ticks with `SchedulerBinding.scheduleFrameCallback` instead of recursive `await _scroll()`.
- Preserve no-progress termination so auto-scroll stops if `moveTo` does not advance the offset.
- Add a `repeat` flag to the editor auto-scroll service.
- Use repeating auto-scroll only for real mobile drag modes (`leftSelectionHandle`, `rightSelectionHandle`, `cursor`). Use one-shot auto-scroll for ordinary mobile selection/caret updates.

### Verification

On the physical Galaxy S23+:

- The original two-tap table interaction no longer ANRs.
- No new Android Dropbox ANR was written after the fix.
- Screenshots taken shortly after re-entering a table and again two seconds later were stable, with no continuing vibration.
- Manual selection around the table looked stable.

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.