Skip to content

Do not wait until dispose before removing replaced/popped page#182315

Merged
auto-submit[bot] merged 7 commits into
masterfrom
navigator-flicker-fix
Feb 17, 2026
Merged

Do not wait until dispose before removing replaced/popped page#182315
auto-submit[bot] merged 7 commits into
masterfrom
navigator-flicker-fix

Conversation

@victorsanni

Copy link
Copy Markdown
Contributor

Regression was introduced in Cleans up navigator pop and remove logic.

That PR moved the onDidRemovePage call to _flushHistoryUpdates in phase _RouteLifecycle.dispose. But waiting until dispose causes potential problems if the widget is rebuilt in a phase preceding that (but after pop or pushReplacement has been called). So the outdated page remains in the pages list even after it has been marked for removal.

This is causing the page to be pushed again before it is finally removed, causing the flicker.

Before

bad.navigator.mov

After

good.navigator.mov

Fixes [Navigation] Popping a nested route while the parent is rebuilding causes a flicker

@flutter-dashboard

Copy link
Copy Markdown

It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

@victorsanni victorsanni requested a review from justinmc February 12, 2026 19:20
@github-actions github-actions Bot added framework flutter/packages/flutter repository. See also f: labels. f: routes Navigator, Router, and related APIs. labels Feb 12, 2026
@victorsanni victorsanni requested a review from chunhtai February 12, 2026 19:20

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses a regression that caused a flicker effect when popping or replacing a nested route. The issue stemmed from onDidRemovePage being called too late in the _RouteLifecycle.dispose phase. The fix correctly moves the onDidRemovePage call to happen immediately within handlePop and handlePush (for replacements), ensuring the navigator's page list is updated promptly and preventing the outdated page from being rebuilt. The changes look correct and effectively resolve the described problem. I've added one suggestion to refactor the newly added code blocks into a helper method to reduce duplication and improve maintainability.

Comment on lines +3272 to +3275
if (previousPresent != null && previousPresent._isPageBased) {
final page = previousPresent.settings as Page<Object?>;
navigator.widget.onDidRemovePage?.call(page);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This logic is very similar to the code added in _RouteEntry.handlePop (lines 3332-3335). To improve maintainability and avoid duplication, consider extracting this into a shared private helper method within _RouteEntry.

For example:

void _didRemovePage(NavigatorState navigator, Route<dynamic> removedRoute) {
  assert(removedRoute._isPageBased);
  final page = removedRoute.settings as Page<Object?>;
  navigator.widget.onDidRemovePage?.call(page);
}

You could then call this helper from both handlePush and handlePop.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way 🤷

@justinmc justinmc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approach looks good. Are you sure that replace and pop are the only two things that can result in needing to call onDidRemovePage?

Comment on lines +3272 to +3275
if (previousPresent != null && previousPresent._isPageBased) {
final page = previousPresent.settings as Page<Object?>;
navigator.widget.onDidRemovePage?.call(page);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either way 🤷

@victorsanni

Copy link
Copy Markdown
Contributor Author

Are you sure that replace and pop are the only two things that can result in needing to call onDidRemovePage?

Maybe removeRoute, but calling that method means the user already has the route to be removed, so they can just call onDidRemovePage(route.settings) directly I think?

@victorsanni victorsanni requested a review from justinmc February 12, 2026 23:20

@justinmc justinmc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍 . Heads up there's an analyzer failure.

Maybe removeRoute, but calling that method means the user already has the route to be removed, so they can just call onDidRemovePage(route.settings) directly I think?

Sounds good as long as the tests pass.

Comment thread packages/flutter/test/widgets/navigator_on_did_remove_page_test.dart Outdated

@chunhtai chunhtai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@victorsanni victorsanni added the autosubmit Merge PR when tree becomes green via auto submit App label Feb 17, 2026
@auto-submit auto-submit Bot added this pull request to the merge queue Feb 17, 2026
Merged via the queue into master with commit 7ac16a2 Feb 17, 2026
77 checks passed
@auto-submit auto-submit Bot deleted the navigator-flicker-fix branch February 17, 2026 21:19
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Feb 17, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 18, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 18, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 18, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 18, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 18, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Feb 18, 2026
…11060)

Manual roll requested by tarrinneal@google.com

flutter/flutter@6e4a481...c023e5b

2026-02-18 zhongliu88889@gmail.com [web] Pass form validation errors to screen readers via aria-description (flutter/flutter#180556)
2026-02-18 engine-flutter-autoroll@skia.org Roll Packages from f83926f to 59f905c (10 revisions) (flutter/flutter#182547)
2026-02-18 104147021+MohammedTarigg@users.noreply.github.com flutter_tools: Copy vendored frameworks from plugin podspecs in ios/macos-framework builds (flutter/flutter#180135)
2026-02-18 fluttergithubbot@gmail.com Marks Windows framework_tests_misc_leak_tracking to be unflaky (flutter/flutter#182534)
2026-02-18 brackenavaron@gmail.com Allow TabBar to receive a TabBarScrollController (flutter/flutter#180389)
2026-02-18 brackenavaron@gmail.com Clean up cross imports in single_child_scroll_view_test.dart, decorated_sliver_test.dart, draggable_scrollable_sheet_test.dart (flutter/flutter#181613)
2026-02-18 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from mcN42vw48OPH3JDNm... to Ihau0pUz3u5ajw42u... (flutter/flutter#182530)
2026-02-18 scheglov@google.com Analyzer, require 10.1.0, fix deprecations in dependency_graph.dart (flutter/flutter#182507)
2026-02-17 34465683+rkishan516@users.noreply.github.com Refactor: Remove material from actions test (flutter/flutter#181702)
2026-02-17 jhy03261997@gmail.com [a11y] RangeSlider  mouse interaction should change keyboard focus (flutter/flutter#182185)
2026-02-17 116356835+AbdeMohlbi@users.noreply.github.com Remove more getters from userMessages class (flutter/flutter#182166)
2026-02-17 evanwall@buffalo.edu Implement getUniformMatX and getUniformMatXArray functionality on web (flutter/flutter#182249)
2026-02-17 victorsanniay@gmail.com Do not wait until dispose before removing replaced/popped page (flutter/flutter#182315)
2026-02-17 iliyazelenkog@gmail.com Add contentTextStyle support to SimpleDialog (flutter/flutter#178824)
2026-02-17 alex.medinsh@gmail.com Filter error messages from `emulator -list-avds` output (flutter/flutter#180802)
2026-02-17 brackenavaron@gmail.com [Reland] Cupertino cross imports (flutter/flutter#182416)
2026-02-17 engine-flutter-autoroll@skia.org Roll Packages from 09104b0 to f83926f (1 revision) (flutter/flutter#182504)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC stuartmorgan@google.com,tarrinneal@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
rickhohler pushed a commit to rickhohler/flutter that referenced this pull request Feb 19, 2026
…er#182315)

Regression was introduced in [Cleans up navigator pop and remove
logic](https://github.com/flutter/flutter/pull/175612/changes#top).

That PR moved the `onDidRemovePage` call to `_flushHistoryUpdates` in
phase `_RouteLifecycle.dispose`. But waiting until `dispose` causes
potential problems if the widget is rebuilt in a phase preceding that
(but after `pop` or `pushReplacement` has been called). So the outdated
page remains in the pages list even after it has been marked for
removal.

This is causing the page to be pushed again before it is finally
removed, causing the flicker.

## Before


https://github.com/user-attachments/assets/73dba22d-e668-4b2d-84f3-a0beb1faebab



## After


https://github.com/user-attachments/assets/6c8c6ffc-87f0-494f-bd41-7fde1f21d0e1



Fixes [[Navigation] Popping a nested route while the parent is
rebuilding causes a
flicker](flutter#178570)
ahmedsameha1 pushed a commit to ahmedsameha1/flutter that referenced this pull request Feb 27, 2026
…er#182315)

Regression was introduced in [Cleans up navigator pop and remove
logic](https://github.com/flutter/flutter/pull/175612/changes#top).

That PR moved the `onDidRemovePage` call to `_flushHistoryUpdates` in
phase `_RouteLifecycle.dispose`. But waiting until `dispose` causes
potential problems if the widget is rebuilt in a phase preceding that
(but after `pop` or `pushReplacement` has been called). So the outdated
page remains in the pages list even after it has been marked for
removal.

This is causing the page to be pushed again before it is finally
removed, causing the flicker.

## Before


https://github.com/user-attachments/assets/73dba22d-e668-4b2d-84f3-a0beb1faebab



## After


https://github.com/user-attachments/assets/6c8c6ffc-87f0-494f-bd41-7fde1f21d0e1



Fixes [[Navigation] Popping a nested route while the parent is
rebuilding causes a
flicker](flutter#178570)
okorohelijah pushed a commit to okorohelijah/packages that referenced this pull request Mar 26, 2026
…lutter#11060)

Manual roll requested by tarrinneal@google.com

flutter/flutter@6e4a481...c023e5b

2026-02-18 zhongliu88889@gmail.com [web] Pass form validation errors to screen readers via aria-description (flutter/flutter#180556)
2026-02-18 engine-flutter-autoroll@skia.org Roll Packages from f83926f to 59f905c (10 revisions) (flutter/flutter#182547)
2026-02-18 104147021+MohammedTarigg@users.noreply.github.com flutter_tools: Copy vendored frameworks from plugin podspecs in ios/macos-framework builds (flutter/flutter#180135)
2026-02-18 fluttergithubbot@gmail.com Marks Windows framework_tests_misc_leak_tracking to be unflaky (flutter/flutter#182534)
2026-02-18 brackenavaron@gmail.com Allow TabBar to receive a TabBarScrollController (flutter/flutter#180389)
2026-02-18 brackenavaron@gmail.com Clean up cross imports in single_child_scroll_view_test.dart, decorated_sliver_test.dart, draggable_scrollable_sheet_test.dart (flutter/flutter#181613)
2026-02-18 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from mcN42vw48OPH3JDNm... to Ihau0pUz3u5ajw42u... (flutter/flutter#182530)
2026-02-18 scheglov@google.com Analyzer, require 10.1.0, fix deprecations in dependency_graph.dart (flutter/flutter#182507)
2026-02-17 34465683+rkishan516@users.noreply.github.com Refactor: Remove material from actions test (flutter/flutter#181702)
2026-02-17 jhy03261997@gmail.com [a11y] RangeSlider  mouse interaction should change keyboard focus (flutter/flutter#182185)
2026-02-17 116356835+AbdeMohlbi@users.noreply.github.com Remove more getters from userMessages class (flutter/flutter#182166)
2026-02-17 evanwall@buffalo.edu Implement getUniformMatX and getUniformMatXArray functionality on web (flutter/flutter#182249)
2026-02-17 victorsanniay@gmail.com Do not wait until dispose before removing replaced/popped page (flutter/flutter#182315)
2026-02-17 iliyazelenkog@gmail.com Add contentTextStyle support to SimpleDialog (flutter/flutter#178824)
2026-02-17 alex.medinsh@gmail.com Filter error messages from `emulator -list-avds` output (flutter/flutter#180802)
2026-02-17 brackenavaron@gmail.com [Reland] Cupertino cross imports (flutter/flutter#182416)
2026-02-17 engine-flutter-autoroll@skia.org Roll Packages from 09104b0 to f83926f (1 revision) (flutter/flutter#182504)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC stuartmorgan@google.com,tarrinneal@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
mboetger pushed a commit to mboetger/flutter that referenced this pull request Mar 26, 2026
…er#182315)

Regression was introduced in [Cleans up navigator pop and remove
logic](https://github.com/flutter/flutter/pull/175612/changes#top).

That PR moved the `onDidRemovePage` call to `_flushHistoryUpdates` in
phase `_RouteLifecycle.dispose`. But waiting until `dispose` causes
potential problems if the widget is rebuilt in a phase preceding that
(but after `pop` or `pushReplacement` has been called). So the outdated
page remains in the pages list even after it has been marked for
removal.

This is causing the page to be pushed again before it is finally
removed, causing the flicker.

## Before


https://github.com/user-attachments/assets/73dba22d-e668-4b2d-84f3-a0beb1faebab



## After


https://github.com/user-attachments/assets/6c8c6ffc-87f0-494f-bd41-7fde1f21d0e1



Fixes [[Navigation] Popping a nested route while the parent is
rebuilding causes a
flicker](flutter#178570)
creatorpiyush pushed a commit to creatorpiyush/packages that referenced this pull request Jun 10, 2026
…lutter#11060)

Manual roll requested by tarrinneal@google.com

flutter/flutter@6e4a481...c023e5b

2026-02-18 zhongliu88889@gmail.com [web] Pass form validation errors to screen readers via aria-description (flutter/flutter#180556)
2026-02-18 engine-flutter-autoroll@skia.org Roll Packages from f83926f to 59f905c (10 revisions) (flutter/flutter#182547)
2026-02-18 104147021+MohammedTarigg@users.noreply.github.com flutter_tools: Copy vendored frameworks from plugin podspecs in ios/macos-framework builds (flutter/flutter#180135)
2026-02-18 fluttergithubbot@gmail.com Marks Windows framework_tests_misc_leak_tracking to be unflaky (flutter/flutter#182534)
2026-02-18 brackenavaron@gmail.com Allow TabBar to receive a TabBarScrollController (flutter/flutter#180389)
2026-02-18 brackenavaron@gmail.com Clean up cross imports in single_child_scroll_view_test.dart, decorated_sliver_test.dart, draggable_scrollable_sheet_test.dart (flutter/flutter#181613)
2026-02-18 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from mcN42vw48OPH3JDNm... to Ihau0pUz3u5ajw42u... (flutter/flutter#182530)
2026-02-18 scheglov@google.com Analyzer, require 10.1.0, fix deprecations in dependency_graph.dart (flutter/flutter#182507)
2026-02-17 34465683+rkishan516@users.noreply.github.com Refactor: Remove material from actions test (flutter/flutter#181702)
2026-02-17 jhy03261997@gmail.com [a11y] RangeSlider  mouse interaction should change keyboard focus (flutter/flutter#182185)
2026-02-17 116356835+AbdeMohlbi@users.noreply.github.com Remove more getters from userMessages class (flutter/flutter#182166)
2026-02-17 evanwall@buffalo.edu Implement getUniformMatX and getUniformMatXArray functionality on web (flutter/flutter#182249)
2026-02-17 victorsanniay@gmail.com Do not wait until dispose before removing replaced/popped page (flutter/flutter#182315)
2026-02-17 iliyazelenkog@gmail.com Add contentTextStyle support to SimpleDialog (flutter/flutter#178824)
2026-02-17 alex.medinsh@gmail.com Filter error messages from `emulator -list-avds` output (flutter/flutter#180802)
2026-02-17 brackenavaron@gmail.com [Reland] Cupertino cross imports (flutter/flutter#182416)
2026-02-17 engine-flutter-autoroll@skia.org Roll Packages from 09104b0 to f83926f (1 revision) (flutter/flutter#182504)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC stuartmorgan@google.com,tarrinneal@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

f: routes Navigator, Router, and related APIs. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Navigation] Popping a nested route while the parent is rebuilding causes a flicker

3 participants