Unverified Commit 6cfb86fb authored by chunhtai's avatar chunhtai Committed by GitHub

Fix crash if update pages right after a navigator pop (#68923)

parent 27e1efc1
......@@ -985,11 +985,15 @@ class DefaultTransitionDelegate<T> extends TransitionDelegate<T> {
if (hasPagelessRoute) {
final List<RouteTransitionRecord> pagelessRoutes = pageRouteToPagelessRoutes[exitingPageRoute]!;
for (final RouteTransitionRecord pagelessRoute in pagelessRoutes) {
assert(pagelessRoute.isWaitingForExitingDecision);
if (isLastExitingPageRoute && pagelessRoute == pagelessRoutes.last) {
pagelessRoute.markForPop(pagelessRoute.route.currentResult);
} else {
pagelessRoute.markForComplete(pagelessRoute.route.currentResult);
// It is possible that a pageless route that belongs to an exiting
// page-based route does not require exiting decision. This can
// happen if the page list is updated right after a Navigator.pop.
if (pagelessRoute.isWaitingForExitingDecision) {
if (isLastExitingPageRoute && pagelessRoute == pagelessRoutes.last) {
pagelessRoute.markForPop(pagelessRoute.route.currentResult);
} else {
pagelessRoute.markForComplete(pagelessRoute.route.currentResult);
}
}
}
}
......@@ -3655,7 +3659,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
() => <_RouteEntry>[],
);
pagelessRoutes.add(potentialEntryToRemove);
if (previousOldPageRouteEntry!.isWaitingForExitingDecision)
if (previousOldPageRouteEntry!.isWaitingForExitingDecision && potentialEntryToRemove.isPresent)
potentialEntryToRemove.markNeedsExitingDecision();
continue;
}
......
......@@ -3195,6 +3195,43 @@ void main() {
expect(find.text('initial'), findsOneWidget);
});
testWidgets('can update pages before a pageless route has finished popping', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/68162.
final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
List<Page<dynamic>> myPages = <TestPage>[
const TestPage(key: ValueKey<String>('1'), name: 'initial'),
const TestPage(key: ValueKey<String>('2'), name: 'second'),
];
bool onPopPage(Route<dynamic> route, dynamic result) {
myPages.removeWhere((Page<dynamic> page) => route.settings == page);
return route.didPop(result);
}
await tester.pumpWidget(
buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator)
);
// Pushes a pageless route.
showDialog<void>(
useRootNavigator: false,
context: navigator.currentContext!,
builder: (BuildContext context) => const Text('dialog')
);
await tester.pumpAndSettle();
expect(find.text('dialog'), findsOneWidget);
// Pops the pageless route.
navigator.currentState!.pop();
// Before the pop finishes, updates the page list.
myPages = <TestPage>[
const TestPage(key: ValueKey<String>('1'), name: 'initial'),
];
await tester.pumpWidget(
buildNavigator(pages: myPages, onPopPage: onPopPage, key: navigator)
);
// It should not crash the app.
expect(tester.takeException(), isNull);
await tester.pumpAndSettle();
expect(find.text('initial'), findsOneWidget);
});
testWidgets('pages remove and add trigger observer in the right order', (WidgetTester tester) async {
final GlobalKey<NavigatorState> navigator = GlobalKey<NavigatorState>();
List<TestPage> myPages = <TestPage>[
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment