AppFlowy-IO / AppFlowy-IO/appflowy-editor

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

Đang mở
#1,215 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Dart
Star
684
Fork
329
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

### 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.

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.