Add timeline events for post frame callbacks (#136435)
Before this change, long-running post-frame callbacks wouldn't show up in the timeline at all. This adds a timeline event for post-frame callbacks, with a debug flag that will add timeline events for each individual callback.
#testexempt -- we have no way to test calls to the timeline.
diff --git a/packages/flutter/lib/src/cupertino/context_menu.dart b/packages/flutter/lib/src/cupertino/context_menu.dart
index 385bae1..5361c2f 100644
--- a/packages/flutter/lib/src/cupertino/context_menu.dart
+++ b/packages/flutter/lib/src/cupertino/context_menu.dart
@@ -585,7 +585,7 @@
_lastOverlayEntry?.dispose();
_lastOverlayEntry = null;
_openController.reset();
- });
+ }, debugLabel: 'removeContextMenuDecoy');
case AnimationStatus.forward:
case AnimationStatus.reverse:
@@ -1009,7 +1009,7 @@
_updateTweenRects();
_internalOffstage = false;
_setOffstageInternally();
- });
+ }, debugLabel: 'renderContextMenuRouteOffstage');
return super.didPush();
}
diff --git a/packages/flutter/lib/src/cupertino/date_picker.dart b/packages/flutter/lib/src/cupertino/date_picker.dart
index dc15ea3..a76da3f 100644
--- a/packages/flutter/lib/src/cupertino/date_picker.dart
+++ b/packages/flutter/lib/src/cupertino/date_picker.dart
@@ -1007,7 +1007,7 @@
final int position = minCheck ? positionDouble.ceil() : positionDouble.floor();
_animateColumnControllerToItem(minuteController, position);
}
- });
+ }, debugLabel: 'DatePicker.scrollToDate');
}
@override
@@ -1401,7 +1401,7 @@
if (selectedDay != newDate.day) {
_animateColumnControllerToItem(dayController, newDate.day - 1);
}
- });
+ }, debugLabel: 'DatePicker.scrollToDate');
}
@override
@@ -1725,7 +1725,7 @@
if (selectedMonth != newDate.month) {
_animateColumnControllerToItem(monthController, newDate.month - 1);
}
- });
+ }, debugLabel: 'DatePicker.scrollToDate');
}
@override
diff --git a/packages/flutter/lib/src/cupertino/refresh.dart b/packages/flutter/lib/src/cupertino/refresh.dart
index c4e1852..507758b 100644
--- a/packages/flutter/lib/src/cupertino/refresh.dart
+++ b/packages/flutter/lib/src/cupertino/refresh.dart
@@ -461,7 +461,7 @@
} else {
SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
setState(() => hasSliverLayoutExtent = false);
- });
+ }, debugLabel: 'Refresh.goToDone');
}
}
@@ -497,7 +497,7 @@
}
});
setState(() => hasSliverLayoutExtent = true);
- });
+ }, debugLabel: 'Refresh.transition');
}
return RefreshIndicatorMode.armed;
}
diff --git a/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart b/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart
index 641780e..2e100c1 100644
--- a/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart
+++ b/packages/flutter/lib/src/cupertino/spell_check_suggestions_toolbar.dart
@@ -130,7 +130,7 @@
if (editableTextState.mounted) {
editableTextState.bringIntoView(editableTextState.textEditingValue.selection.extent);
}
- });
+ }, debugLabel: 'SpellCheckSuggestions.bringIntoView');
editableTextState.hideToolbar();
}
diff --git a/packages/flutter/lib/src/gestures/binding.dart b/packages/flutter/lib/src/gestures/binding.dart
index ccb6be3..0dec4b0 100644
--- a/packages/flutter/lib/src/gestures/binding.dart
+++ b/packages/flutter/lib/src/gestures/binding.dart
@@ -175,7 +175,7 @@
_timer = Timer.periodic(_samplingInterval, (_) => _onSampleTimeChanged());
// Trigger an immediate sample time change.
_onSampleTimeChanged();
- });
+ }, debugLabel: 'Resampler.startTimer');
}
}
diff --git a/packages/flutter/lib/src/material/autocomplete.dart b/packages/flutter/lib/src/material/autocomplete.dart
index c078018..aea1276 100644
--- a/packages/flutter/lib/src/material/autocomplete.dart
+++ b/packages/flutter/lib/src/material/autocomplete.dart
@@ -201,7 +201,7 @@
if (highlight) {
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
Scrollable.ensureVisible(context, alignment: 0.5);
- });
+ }, debugLabel: 'AutocompleteOptions.ensureVisible');
}
return Container(
color: highlight ? Theme.of(context).focusColor : null,
diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart
index 0b74b39..1966b5f 100644
--- a/packages/flutter/lib/src/material/dropdown_menu.dart
+++ b/packages/flutter/lib/src/material/dropdown_menu.dart
@@ -423,7 +423,7 @@
setState(() {
leadingPadding = getWidth(_leadingKey);
});
- });
+ }, debugLabel: 'DropdownMenu.refreshLeadingPadding');
}
void scrollToHighlight() {
@@ -432,7 +432,7 @@
if (highlightContext != null) {
Scrollable.ensureVisible(highlightContext);
}
- });
+ }, debugLabel: 'DropdownMenu.scrollToHighlight');
}
double? getWidth(GlobalKey key) {
diff --git a/packages/flutter/lib/src/material/input_date_picker_form_field.dart b/packages/flutter/lib/src/material/input_date_picker_form_field.dart
index a7600e4..5bd0167 100644
--- a/packages/flutter/lib/src/material/input_date_picker_form_field.dart
+++ b/packages/flutter/lib/src/material/input_date_picker_form_field.dart
@@ -174,7 +174,7 @@
_selectedDate = widget.initialDate;
_updateValueForSelectedDate();
});
- });
+ }, debugLabel: 'InputDatePickerFormField.update');
}
}
diff --git a/packages/flutter/lib/src/material/menu_anchor.dart b/packages/flutter/lib/src/material/menu_anchor.dart
index 2f0c3a4..aa54f3b 100644
--- a/packages/flutter/lib/src/material/menu_anchor.dart
+++ b/packages/flutter/lib/src/material/menu_anchor.dart
@@ -583,7 +583,7 @@
} else if (!inDispose) {
SchedulerBinding.instance.addPostFrameCallback((_) {
_overlayController.hide();
- });
+ }, debugLabel: 'MenuAnchor.hide');
}
if (!inDispose) {
// Notify that _childIsOpen changed state, but only if not
@@ -1150,7 +1150,7 @@
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
FocusManager.instance.applyFocusChangesIfNeeded();
widget.onPressed?.call();
- });
+ }, debugLabel: 'MenuAnchor.onPressed');
}
void _createInternalFocusNodeIfNeeded() {
@@ -1902,7 +1902,7 @@
SchedulerBinding.instance.addPostFrameCallback((_) {
_menuController._anchor?._focusButton();
_waitingToFocusMenu = false;
- });
+ }, debugLabel: 'MenuAnchor.focus');
_waitingToFocusMenu = true;
}
setState(() { /* Rebuild with updated controller.isOpen value */ });
diff --git a/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart b/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart
index cf0c218..35aa913 100644
--- a/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart
+++ b/packages/flutter/lib/src/material/spell_check_suggestions_toolbar.dart
@@ -142,7 +142,7 @@
if (editableTextState.mounted) {
editableTextState.bringIntoView(editableTextState.textEditingValue.selection.extent);
}
- });
+ }, debugLabel: 'SpellCheckerSuggestionsToolbar.bringIntoView');
editableTextState.hideToolbar();
}
diff --git a/packages/flutter/lib/src/material/tabs.dart b/packages/flutter/lib/src/material/tabs.dart
index 235e611..146e5db 100644
--- a/packages/flutter/lib/src/material/tabs.dart
+++ b/packages/flutter/lib/src/material/tabs.dart
@@ -1507,7 +1507,7 @@
}
return true;
}());
- });
+ }, debugLabel: 'TabBar.tabsCountCheck');
_debugHasScheduledValidTabsCountCheck = true;
return true;
}
@@ -2024,7 +2024,7 @@
}
return true;
}());
- });
+ }, debugLabel: 'TabBarView.validChildrenCountCheck');
_debugHasScheduledValidChildrenCountCheck = true;
return true;
}
diff --git a/packages/flutter/lib/src/painting/decoration_image.dart b/packages/flutter/lib/src/painting/decoration_image.dart
index 62ea98b..eb9f765 100644
--- a/packages/flutter/lib/src/painting/decoration_image.dart
+++ b/packages/flutter/lib/src/painting/decoration_image.dart
@@ -655,7 +655,7 @@
},
);
_pendingImageSizeInfo = <String, ImageSizeInfo>{};
- });
+ }, debugLabel: 'paintImage.recordImageSizes');
}
}
diff --git a/packages/flutter/lib/src/painting/image_cache.dart b/packages/flutter/lib/src/painting/image_cache.dart
index f8ddad8..04b69a3 100644
--- a/packages/flutter/lib/src/painting/image_cache.dart
+++ b/packages/flutter/lib/src/painting/image_cache.dart
@@ -621,7 +621,7 @@
assert(handle != null);
handle?.dispose();
handle = null;
- });
+ }, debugLabel: 'CachedImage.disposeHandle');
}
}
diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart
index ff7d2de..82bb2bd 100644
--- a/packages/flutter/lib/src/rendering/binding.dart
+++ b/packages/flutter/lib/src/rendering/binding.dart
@@ -46,7 +46,7 @@
addPersistentFrameCallback(_handlePersistentFrameCallback);
initMouseTracker();
if (kIsWeb) {
- addPostFrameCallback(_handleWebFirstFrame);
+ addPostFrameCallback(_handleWebFirstFrame, debugLabel: 'RendererBinding.webFirstFrame');
}
rootPipelineOwner.attach(_manifold);
}
@@ -463,7 +463,7 @@
return true;
}());
_mouseTracker!.updateAllDevices();
- });
+ }, debugLabel: 'RendererBinding.mouseTrackerUpdate');
}
int _firstFrameDeferredCount = 0;
diff --git a/packages/flutter/lib/src/rendering/layer.dart b/packages/flutter/lib/src/rendering/layer.dart
index f2bd274..2bf31c4 100644
--- a/packages/flutter/lib/src/rendering/layer.dart
+++ b/packages/flutter/lib/src/rendering/layer.dart
@@ -2337,7 +2337,7 @@
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
_debugLeaderCheckScheduled = false;
assert(_debugPreviousLeaders!.isEmpty);
- });
+ }, debugLabel: 'LayerLink.leadersCleanUpCheck');
return true;
}());
}
diff --git a/packages/flutter/lib/src/rendering/platform_view.dart b/packages/flutter/lib/src/rendering/platform_view.dart
index e3f4cdb..e92489d 100644
--- a/packages/flutter/lib/src/rendering/platform_view.dart
+++ b/packages/flutter/lib/src/rendering/platform_view.dart
@@ -202,7 +202,7 @@
// Schedule a new post frame callback.
_setOffset();
}
- });
+ }, debugLabel: 'RenderAndroidView.setOffset');
}
@override
diff --git a/packages/flutter/lib/src/scheduler/binding.dart b/packages/flutter/lib/src/scheduler/binding.dart
index b2cc42b..039ddfc 100644
--- a/packages/flutter/lib/src/scheduler/binding.dart
+++ b/packages/flutter/lib/src/scheduler/binding.dart
@@ -765,6 +765,13 @@
///
/// Post-frame callbacks cannot be unregistered. They are called exactly once.
///
+ /// In debug mode, if [debugTracePostFrameCallbacks] is set to true, then the
+ /// registered callback will show up in the timeline events chart, which can
+ /// be viewed in [DevTools](https://docs.flutter.dev/tools/devtools/overview).
+ /// In that case, the `debugLabel` argument specifies the name of the callback
+ /// as it will appear in the timeline. In profile and release builds,
+ /// post-frame are never traced, and the `debugLabel` argument is ignored.
+ ///
/// See also:
///
/// * [scheduleFrameCallback], which registers a callback for the start of
@@ -772,7 +779,21 @@
/// * [WidgetsBinding.drawFrame], which explains the phases of each frame
/// for those apps that use Flutter widgets (and where post frame
/// callbacks fit into those phases).
- void addPostFrameCallback(FrameCallback callback) {
+ void addPostFrameCallback(FrameCallback callback, {String debugLabel = 'callback'}) {
+ assert(() {
+ if (debugTracePostFrameCallbacks) {
+ final FrameCallback originalCallback = callback;
+ callback = (Duration timeStamp) {
+ Timeline.startSync(debugLabel);
+ try {
+ originalCallback(timeStamp);
+ } finally {
+ Timeline.finishSync();
+ }
+ };
+ }
+ return true;
+ }());
_postFrameCallbacks.add(callback);
}
@@ -796,7 +817,7 @@
addPostFrameCallback((Duration timeStamp) {
_nextFrameCompleter!.complete();
_nextFrameCompleter = null;
- });
+ }, debugLabel: 'SchedulerBinding.completeFrame');
}
return _nextFrameCompleter!.future;
}
@@ -1127,7 +1148,7 @@
// still be true here and cause us to skip scheduling an engine frame.
_hasScheduledFrame = false;
scheduleFrame();
- });
+ }, debugLabel: 'SchedulerBinding.scheduleFrame');
return;
}
handleDrawFrame();
@@ -1280,8 +1301,13 @@
final List<FrameCallback> localPostFrameCallbacks =
List<FrameCallback>.of(_postFrameCallbacks);
_postFrameCallbacks.clear();
- for (final FrameCallback callback in localPostFrameCallbacks) {
- _invokeFrameCallback(callback, _currentFrameTimeStamp!);
+ Timeline.startSync('POST_FRAME');
+ try {
+ for (final FrameCallback callback in localPostFrameCallbacks) {
+ _invokeFrameCallback(callback, _currentFrameTimeStamp!);
+ }
+ } finally {
+ Timeline.finishSync();
}
} finally {
_schedulerPhase = SchedulerPhase.idle;
diff --git a/packages/flutter/lib/src/scheduler/debug.dart b/packages/flutter/lib/src/scheduler/debug.dart
index 82af69f..3be545f 100644
--- a/packages/flutter/lib/src/scheduler/debug.dart
+++ b/packages/flutter/lib/src/scheduler/debug.dart
@@ -48,6 +48,20 @@
/// [debugPrintScheduleBuildForStacks].
bool debugPrintScheduleFrameStacks = false;
+/// Record timeline trace events for post-frame callbacks.
+///
+/// When this flag is set to false (the default), the developer timeline
+/// records when post-frame callbacks are running, but it does not tell you any
+/// information about how that time is spent within specific callbacks:
+///
+/// 
+///
+/// When this flag is set to true, timeline events will be recorded for each
+/// post-frame callback that runs, like so:
+///
+/// 
+bool debugTracePostFrameCallbacks = false;
+
/// Returns true if none of the scheduler library debug variables have been changed.
///
/// This function is used by the test framework to ensure that debug variables
diff --git a/packages/flutter/lib/src/services/restoration.dart b/packages/flutter/lib/src/services/restoration.dart
index 694f2f6..b188ec1 100644
--- a/packages/flutter/lib/src/services/restoration.dart
+++ b/packages/flutter/lib/src/services/restoration.dart
@@ -268,7 +268,7 @@
if (_isReplacing) {
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
_isReplacing = false;
- });
+ }, debugLabel: 'RestorationManager.resetIsReplacing');
}
final RestorationBucket? oldRoot = _rootBucket;
@@ -349,7 +349,10 @@
_bucketsNeedingSerialization.add(bucket);
if (!_serializationScheduled) {
_serializationScheduled = true;
- SchedulerBinding.instance.addPostFrameCallback((Duration _) => _doSerialization());
+ SchedulerBinding.instance.addPostFrameCallback(
+ (Duration _) => _doSerialization(),
+ debugLabel: 'RestorationManager.doSerialization'
+ );
}
}
diff --git a/packages/flutter/lib/src/widgets/actions.dart b/packages/flutter/lib/src/widgets/actions.dart
index 6d373b8..beba13b 100644
--- a/packages/flutter/lib/src/widgets/actions.dart
+++ b/packages/flutter/lib/src/widgets/actions.dart
@@ -1231,7 +1231,7 @@
super.initState();
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
_updateHighlightMode(FocusManager.instance.highlightMode);
- });
+ }, debugLabel: 'FocusableActionDetector.updateHighlightMode');
FocusManager.instance.addHighlightModeListener(_handleFocusHighlightModeChange);
}
@@ -1339,7 +1339,7 @@
if (widget.enabled != oldWidget.enabled) {
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
_mayTriggerCallback(oldWidget: oldWidget);
- });
+ }, debugLabel: 'FocusableActionDetector.mayTriggerCallback');
}
}
diff --git a/packages/flutter/lib/src/widgets/autocomplete.dart b/packages/flutter/lib/src/widgets/autocomplete.dart
index d44ec4d..d71180a 100644
--- a/packages/flutter/lib/src/widgets/autocomplete.dart
+++ b/packages/flutter/lib/src/widgets/autocomplete.dart
@@ -440,7 +440,7 @@
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
_floatingOptionsUpdateScheduled = false;
_updateOverlay();
- });
+ }, debugLabel: 'RawAutoComplete.updateOverlay');
}
return;
}
diff --git a/packages/flutter/lib/src/widgets/automatic_keep_alive.dart b/packages/flutter/lib/src/widgets/automatic_keep_alive.dart
index a8292b1..bd40d2a 100644
--- a/packages/flutter/lib/src/widgets/automatic_keep_alive.dart
+++ b/packages/flutter/lib/src/widgets/automatic_keep_alive.dart
@@ -99,7 +99,7 @@
final ParentDataElement<KeepAliveParentDataMixin>? childElement = _getChildElement();
assert(childElement != null);
_updateParentDataOfChild(childElement!);
- });
+ }, debugLabel: 'AutomaticKeepAlive.updateParentData');
}
}
return false;
diff --git a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart
index eaf615a..9c7f80b 100644
--- a/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart
+++ b/packages/flutter/lib/src/widgets/draggable_scrollable_sheet.dart
@@ -763,7 +763,7 @@
_scrollController.positions.elementAt(index) as _DraggableScrollableSheetScrollPosition;
position.goBallistic(0);
}
- });
+ }, debugLabel: 'DraggableScrollableSheet.snap');
}
}
diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart
index c4c3765..13ede28 100644
--- a/packages/flutter/lib/src/widgets/editable_text.dart
+++ b/packages/flutter/lib/src/widgets/editable_text.dart
@@ -2390,7 +2390,7 @@
if (mounted) {
bringIntoView(textEditingValue.selection.extent);
}
- });
+ }, debugLabel: 'EditableText.bringSelectionIntoView');
hideToolbar();
}
clipboardStatus.update();
@@ -2430,7 +2430,7 @@
if (mounted) {
bringIntoView(textEditingValue.selection.extent);
}
- });
+ }, debugLabel: 'EditableText.bringSelectionIntoView');
hideToolbar();
}
}
@@ -2818,7 +2818,7 @@
_flagInternalFocus();
FocusScope.of(context).autofocus(widget.focusNode);
}
- });
+ }, debugLabel: 'EditableText.autofocus');
}
// Restart or stop the blinking cursor when TickerMode changes.
@@ -2889,7 +2889,7 @@
// See https://github.com/flutter/flutter/issues/126312
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
_openInputConnection();
- });
+ }, debugLabel: 'EditableText.openInputConnection');
}
if (kIsWeb && _hasInputConnection) {
@@ -3721,7 +3721,7 @@
rect: caretPadding.inflateRect(rectToReveal),
);
}
- });
+ }, debugLabel: 'EditableText.showCaret');
}
late double _lastBottomViewInset;
@@ -3735,7 +3735,7 @@
if (_lastBottomViewInset != view.viewInsets.bottom) {
SchedulerBinding.instance.addPostFrameCallback((Duration _) {
_selectionOverlay?.updateForScroll();
- });
+ }, debugLabel: 'EditableText.updateForScroll');
if (_lastBottomViewInset < view.viewInsets.bottom) {
// Because the metrics change signal from engine will come here every frame
// (on both iOS and Android). So we don't need to show caret with animation.
@@ -4038,7 +4038,10 @@
_updateSelectionRects();
_updateComposingRectIfNeeded();
_updateCaretRectIfNeeded();
- SchedulerBinding.instance.addPostFrameCallback(_schedulePeriodicPostFrameCallbacks);
+ SchedulerBinding.instance.addPostFrameCallback(
+ _schedulePeriodicPostFrameCallbacks,
+ debugLabel: 'EditableText.postFrameCallbacks'
+ );
}
_ScribbleCacheKey? _scribbleCacheKey;
diff --git a/packages/flutter/lib/src/widgets/heroes.dart b/packages/flutter/lib/src/widgets/heroes.dart
index 1edac3c..72a1716 100644
--- a/packages/flutter/lib/src/widgets/heroes.dart
+++ b/packages/flutter/lib/src/widgets/heroes.dart
@@ -902,7 +902,7 @@
return;
}
_startHeroTransition(from, to, flightType, isUserGestureTransition);
- });
+ }, debugLabel: 'HeroController.startTransition');
}
}
diff --git a/packages/flutter/lib/src/widgets/image.dart b/packages/flutter/lib/src/widgets/image.dart
index e2871e5..c318050 100644
--- a/packages/flutter/lib/src/widgets/image.dart
+++ b/packages/flutter/lib/src/widgets/image.dart
@@ -124,7 +124,7 @@
// See ImageCache._liveImages
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
stream.removeListener(listener!);
- });
+ }, debugLabel: 'precacheImage.removeListener');
},
onError: (Object exception, StackTrace? stackTrace) {
if (!completer.isCompleted) {
@@ -1164,7 +1164,10 @@
void _replaceImage({required ImageInfo? info}) {
final ImageInfo? oldImageInfo = _imageInfo;
- SchedulerBinding.instance.addPostFrameCallback((_) => oldImageInfo?.dispose());
+ SchedulerBinding.instance.addPostFrameCallback(
+ (_) => oldImageInfo?.dispose(),
+ debugLabel: 'Image.disposeOldInfo'
+ );
_imageInfo = info;
}
diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart
index 7394a52..7fc2966 100644
--- a/packages/flutter/lib/src/widgets/navigator.dart
+++ b/packages/flutter/lib/src/widgets/navigator.dart
@@ -3509,7 +3509,7 @@
return;
}
notification.dispatch(context);
- });
+ }, debugLabel: 'Navigator.dispatchNotification');
}
}
@@ -3716,7 +3716,7 @@
);
}
}
- });
+ }, debugLabel: 'Navigator.checkHeroControllerOwnership');
}
return true;
}());
diff --git a/packages/flutter/lib/src/widgets/nested_scroll_view.dart b/packages/flutter/lib/src/widgets/nested_scroll_view.dart
index 30ee29f..f222688 100644
--- a/packages/flutter/lib/src/widgets/nested_scroll_view.dart
+++ b/packages/flutter/lib/src/widgets/nested_scroll_view.dart
@@ -1183,11 +1183,9 @@
// the position change notifications because those happen synchronously
// during a frame, at a time where it's too late to call setState. Since the
// result is usually animated, the lag incurred is no big deal.
- SchedulerBinding.instance.addPostFrameCallback(
- (Duration timeStamp) {
- coordinator.updateShadow();
- },
- );
+ SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
+ coordinator.updateShadow();
+ }, debugLabel: 'NestedScrollController.updateShadow');
}
Iterable<_NestedScrollPosition> get nestedPositions {
diff --git a/packages/flutter/lib/src/widgets/overlay.dart b/packages/flutter/lib/src/widgets/overlay.dart
index 3cafb4f..cc98507 100644
--- a/packages/flutter/lib/src/widgets/overlay.dart
+++ b/packages/flutter/lib/src/widgets/overlay.dart
@@ -177,7 +177,7 @@
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) {
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
overlay._markDirty();
- });
+ }, debugLabel: 'OverlayEntry.markDirty');
} else {
overlay._markDirty();
}
diff --git a/packages/flutter/lib/src/widgets/platform_view.dart b/packages/flutter/lib/src/widgets/platform_view.dart
index 9916b34..e2e2b9b 100644
--- a/packages/flutter/lib/src/widgets/platform_view.dart
+++ b/packages/flutter/lib/src/widgets/platform_view.dart
@@ -1301,7 +1301,7 @@
// A call to `localToGlobal` requires waiting for a frame to render first.
SchedulerBinding.instance.addPostFrameCallback((_) {
onLayout(size, localToGlobal(Offset.zero));
- });
+ }, debugLabel: 'PlatformViewPlaceholderBox.onLayout');
}
}
@@ -1333,6 +1333,6 @@
void disposePostFrame() {
SchedulerBinding.instance.addPostFrameCallback((_) {
dispose();
- });
+ }, debugLabel: 'PlatformViewController.dispose');
}
}
diff --git a/packages/flutter/lib/src/widgets/reorderable_list.dart b/packages/flutter/lib/src/widgets/reorderable_list.dart
index af912e5..8dac18e 100644
--- a/packages/flutter/lib/src/widgets/reorderable_list.dart
+++ b/packages/flutter/lib/src/widgets/reorderable_list.dart
@@ -753,7 +753,7 @@
_dragStartTransitionComplete = false;
SchedulerBinding.instance.addPostFrameCallback((Duration duration) {
_dragStartTransitionComplete = true;
- });
+ }, debugLabel: 'SliverReorderableList.completeDragStartTransition');
_insertIndex = item.index;
_dragInfo = _DragInfo(
diff --git a/packages/flutter/lib/src/widgets/router.dart b/packages/flutter/lib/src/widgets/router.dart
index dc663c4..5541f92 100644
--- a/packages/flutter/lib/src/widgets/router.dart
+++ b/packages/flutter/lib/src/widgets/router.dart
@@ -628,7 +628,10 @@
}
assert(_currentIntentionToReport != null);
_routeInformationReportingTaskScheduled = true;
- SchedulerBinding.instance.addPostFrameCallback(_reportRouteInformation);
+ SchedulerBinding.instance.addPostFrameCallback(
+ _reportRouteInformation,
+ debugLabel: 'Router.reportRouteInfo',
+ );
}
void _reportRouteInformation(Duration timestamp) {
diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart
index 7d8729e..d8e065c 100644
--- a/packages/flutter/lib/src/widgets/routes.dart
+++ b/packages/flutter/lib/src/widgets/routes.dart
@@ -710,7 +710,7 @@
if (isActive) {
changedInternalState();
}
- });
+ }, debugLabel: 'LocalHistoryRoute.changedInternalState');
} else {
changedInternalState();
}
@@ -1672,7 +1672,7 @@
return;
}
notification.dispatch(subtreeContext);
- });
+ }, debugLabel: 'ModalRoute.dispatchNotification');
}
}
diff --git a/packages/flutter/lib/src/widgets/scroll_position.dart b/packages/flutter/lib/src/widgets/scroll_position.dart
index 1a23ce9..2a03d15 100644
--- a/packages/flutter/lib/src/widgets/scroll_position.dart
+++ b/packages/flutter/lib/src/widgets/scroll_position.dart
@@ -468,7 +468,7 @@
notifyListeners();
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
_impliedVelocity = 0;
- });
+ }, debugLabel: 'ScrollPosition.resetVelocity');
}
/// Called whenever scrolling ends, to store the current scroll offset in a
diff --git a/packages/flutter/lib/src/widgets/scrollable.dart b/packages/flutter/lib/src/widgets/scrollable.dart
index 9393be4..5dfcb33 100644
--- a/packages/flutter/lib/src/widgets/scrollable.dart
+++ b/packages/flutter/lib/src/widgets/scrollable.dart
@@ -1167,7 +1167,7 @@
}
_scheduledLayoutChange = false;
layoutDidChange();
- });
+ }, debugLabel: 'ScrollableSelectionContainer.layoutDidChange');
}
/// Stores the scroll offset when a scrollable receives the last
diff --git a/packages/flutter/lib/src/widgets/scrollbar.dart b/packages/flutter/lib/src/widgets/scrollbar.dart
index 6b32305..76891b9 100644
--- a/packages/flutter/lib/src/widgets/scrollbar.dart
+++ b/packages/flutter/lib/src/widgets/scrollbar.dart
@@ -1413,7 +1413,7 @@
}
WidgetsBinding.instance.addPostFrameCallback((Duration duration) {
assert(_debugCheckHasValidScrollPosition());
- });
+ }, debugLabel: 'RawScrollbar.checkScrollPosition');
return true;
}
diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart
index 70369b8..317ed01 100644
--- a/packages/flutter/lib/src/widgets/selectable_region.dart
+++ b/packages/flutter/lib/src/widgets/selectable_region.dart
@@ -677,7 +677,7 @@
}
_scheduledSelectionEndEdgeUpdate = false;
_triggerSelectionEndEdgeUpdate(textGranularity: textGranularity);
- });
+ }, debugLabel: 'SelectableRegion.endEdgeUpdate');
return;
}
}
@@ -731,7 +731,7 @@
}
_scheduledSelectionStartEdgeUpdate = false;
_triggerSelectionStartEdgeUpdate(textGranularity: textGranularity);
- });
+ }, debugLabel: 'SelectableRegion.startEdgeUpdate');
return;
}
}
@@ -1716,7 +1716,10 @@
// safely updated in the same frame in this case.
scheduleMicrotask(runScheduledTask);
} else {
- SchedulerBinding.instance.addPostFrameCallback(runScheduledTask);
+ SchedulerBinding.instance.addPostFrameCallback(
+ runScheduledTask,
+ debugLabel: 'SelectionContainer.runScheduledTask',
+ );
}
}
}
diff --git a/packages/flutter/lib/src/widgets/semantics_debugger.dart b/packages/flutter/lib/src/widgets/semantics_debugger.dart
index 892140f..6b6c69a 100644
--- a/packages/flutter/lib/src/widgets/semantics_debugger.dart
+++ b/packages/flutter/lib/src/widgets/semantics_debugger.dart
@@ -94,7 +94,7 @@
// The generation of the _SemanticsDebuggerListener has changed.
});
}
- });
+ }, debugLabel: 'SemanticsDebugger.update');
}
Offset? _lastPointerDownLocation;
diff --git a/packages/flutter/lib/src/widgets/shortcuts.dart b/packages/flutter/lib/src/widgets/shortcuts.dart
index 293d28e..d211817 100644
--- a/packages/flutter/lib/src/widgets/shortcuts.dart
+++ b/packages/flutter/lib/src/widgets/shortcuts.dart
@@ -1276,7 +1276,7 @@
if (!_disposed) {
notifyListeners();
}
- });
+ }, debugLabel: 'ShortcutRegistry.notifyListeners');
_notificationScheduled = true;
}
}
diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart
index 0ed6718..e85365d 100644
--- a/packages/flutter/lib/src/widgets/text_selection.dart
+++ b/packages/flutter/lib/src/widgets/text_selection.dart
@@ -1454,7 +1454,7 @@
} else if (_spellCheckToolbarController.isShown) {
_spellCheckToolbarController.markNeedsBuild();
}
- });
+ }, debugLabel: 'SelectionOverlay.markNeedsBuild');
} else {
if (_handles != null) {
_handles!.start.markNeedsBuild();
diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart
index 0a794e1..d6e3580 100644
--- a/packages/flutter/lib/src/widgets/widget_inspector.dart
+++ b/packages/flutter/lib/src/widgets/widget_inspector.dart
@@ -2371,7 +2371,7 @@
void _onFrameStart(Duration timeStamp) {
_frameStart = timeStamp;
- SchedulerBinding.instance.addPostFrameCallback(_onFrameEnd);
+ SchedulerBinding.instance.addPostFrameCallback(_onFrameEnd, debugLabel: 'WidgetInspector.onFrameStart');
}
void _onFrameEnd(Duration timeStamp) {
diff --git a/packages/flutter/test/gestures/gesture_binding_resample_event_test.dart b/packages/flutter/test/gestures/gesture_binding_resample_event_test.dart
index a03c4b0..f5a7a54 100644
--- a/packages/flutter/test/gestures/gesture_binding_resample_event_test.dart
+++ b/packages/flutter/test/gestures/gesture_binding_resample_event_test.dart
@@ -33,7 +33,7 @@
}
@override
- int addPostFrameCallback(FrameCallback callback) {
+ int addPostFrameCallback(FrameCallback callback, {String debugLabel = 'callback'}) {
postFrameCallback = callback;
return 0;
}
diff --git a/packages/flutter/test/rendering/mouse_tracker_test_utils.dart b/packages/flutter/test/rendering/mouse_tracker_test_utils.dart
index eb81870..ce4938f 100644
--- a/packages/flutter/test/rendering/mouse_tracker_test_utils.dart
+++ b/packages/flutter/test/rendering/mouse_tracker_test_utils.dart
@@ -70,7 +70,7 @@
// Proxy post-frame callbacks.
@override
- void addPostFrameCallback(void Function(Duration) callback) {
+ void addPostFrameCallback(void Function(Duration) callback, {String debugLabel = 'callback'}) {
postFrameCallbacks.add(callback);
}