Unverified Commit afbb80b2 authored by chunhtai's avatar chunhtai Committed by GitHub

fix navigator observer announcement order (#57605)

* fix navigator observer announcement order

* addressing review comments

* update

* fix analyzer
parent 3e273b14
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async'; import 'dart:async';
import 'dart:collection';
import 'dart:convert'; import 'dart:convert';
import 'dart:developer' as developer; import 'dart:developer' as developer;
...@@ -2335,7 +2336,7 @@ class _RouteEntry extends RouteTransitionRecord { ...@@ -2335,7 +2336,7 @@ class _RouteEntry extends RouteTransitionRecord {
return page.canUpdate(routePage); return page.canUpdate(routePage);
} }
void handleAdd({ @required NavigatorState navigator}) { void handleAdd({ @required NavigatorState navigator, @required Route<dynamic> previousPresent }) {
assert(currentState == _RouteLifecycle.add); assert(currentState == _RouteLifecycle.add);
assert(navigator != null); assert(navigator != null);
assert(navigator._debugLocked); assert(navigator._debugLocked);
...@@ -2344,6 +2345,9 @@ class _RouteEntry extends RouteTransitionRecord { ...@@ -2344,6 +2345,9 @@ class _RouteEntry extends RouteTransitionRecord {
route.install(); route.install();
assert(route.overlayEntries.isNotEmpty); assert(route.overlayEntries.isNotEmpty);
currentState = _RouteLifecycle.adding; currentState = _RouteLifecycle.adding;
navigator._observedRouteAdditions.add(
_NavigatorPushObservation(route, previousPresent)
);
} }
void handlePush({ @required NavigatorState navigator, @required bool isNewFirst, @required Route<dynamic> previous, @required Route<dynamic> previousPresent }) { void handlePush({ @required NavigatorState navigator, @required bool isNewFirst, @required Route<dynamic> previous, @required Route<dynamic> previousPresent }) {
...@@ -2377,12 +2381,14 @@ class _RouteEntry extends RouteTransitionRecord { ...@@ -2377,12 +2381,14 @@ class _RouteEntry extends RouteTransitionRecord {
} }
if (previousState == _RouteLifecycle.replace || previousState == _RouteLifecycle.pushReplace) { if (previousState == _RouteLifecycle.replace || previousState == _RouteLifecycle.pushReplace) {
for (final NavigatorObserver observer in navigator.widget.observers) navigator._observedRouteAdditions.add(
observer.didReplace(newRoute: route, oldRoute: previousPresent); _NavigatorReplaceObservation(route, previousPresent)
);
} else { } else {
assert(previousState == _RouteLifecycle.push); assert(previousState == _RouteLifecycle.push);
for (final NavigatorObserver observer in navigator.widget.observers) navigator._observedRouteAdditions.add(
observer.didPush(route, previousPresent); _NavigatorPushObservation(route, previousPresent)
);
} }
} }
...@@ -2396,8 +2402,9 @@ class _RouteEntry extends RouteTransitionRecord { ...@@ -2396,8 +2402,9 @@ class _RouteEntry extends RouteTransitionRecord {
assert(navigator._debugLocked); assert(navigator._debugLocked);
assert(route._navigator == navigator); assert(route._navigator == navigator);
currentState = _RouteLifecycle.popping; currentState = _RouteLifecycle.popping;
for (final NavigatorObserver observer in navigator.widget.observers) navigator._observedRouteDeletions.add(
observer.didPop(route, previousPresent); _NavigatorPopObservation(route, previousPresent)
);
} }
void handleRemoval({ @required NavigatorState navigator, @required Route<dynamic> previousPresent }) { void handleRemoval({ @required NavigatorState navigator, @required Route<dynamic> previousPresent }) {
...@@ -2406,21 +2413,20 @@ class _RouteEntry extends RouteTransitionRecord { ...@@ -2406,21 +2413,20 @@ class _RouteEntry extends RouteTransitionRecord {
assert(route._navigator == navigator); assert(route._navigator == navigator);
currentState = _RouteLifecycle.removing; currentState = _RouteLifecycle.removing;
if (_reportRemovalToObserver) { if (_reportRemovalToObserver) {
for (final NavigatorObserver observer in navigator.widget.observers) navigator._observedRouteDeletions.add(
observer.didRemove(route, previousPresent); _NavigatorRemoveObservation(route, previousPresent)
);
} }
} }
bool doingPop = false; bool doingPop = false;
void didAdd({ @required NavigatorState navigator, @required bool isNewFirst, @required Route<dynamic> previous, @required Route<dynamic> previousPresent }) { void didAdd({ @required NavigatorState navigator, @required bool isNewFirst}) {
route.didAdd(); route.didAdd();
currentState = _RouteLifecycle.idle; currentState = _RouteLifecycle.idle;
if (isNewFirst) { if (isNewFirst) {
route.didChangeNext(null); route.didChangeNext(null);
} }
for (final NavigatorObserver observer in navigator.widget.observers)
observer.didPush(route, previousPresent);
} }
void pop<T>(T result) { void pop<T>(T result) {
...@@ -2579,10 +2585,71 @@ class _RouteEntry extends RouteTransitionRecord { ...@@ -2579,10 +2585,71 @@ class _RouteEntry extends RouteTransitionRecord {
} }
} }
abstract class _NavigatorObservation {
_NavigatorObservation(
this.primaryRoute,
this.secondaryRoute,
);
final Route<dynamic> primaryRoute;
final Route<dynamic> secondaryRoute;
void notify(NavigatorObserver observer);
}
class _NavigatorPushObservation extends _NavigatorObservation {
_NavigatorPushObservation(
Route<dynamic> primaryRoute,
Route<dynamic> secondaryRoute
) : super(primaryRoute, secondaryRoute);
@override
void notify(NavigatorObserver observer) {
observer.didPush(primaryRoute, secondaryRoute);
}
}
class _NavigatorPopObservation extends _NavigatorObservation {
_NavigatorPopObservation(
Route<dynamic> primaryRoute,
Route<dynamic> secondaryRoute
) : super(primaryRoute, secondaryRoute);
@override
void notify(NavigatorObserver observer) {
observer.didPop(primaryRoute, secondaryRoute);
}
}
class _NavigatorRemoveObservation extends _NavigatorObservation {
_NavigatorRemoveObservation(
Route<dynamic> primaryRoute,
Route<dynamic> secondaryRoute
) : super(primaryRoute, secondaryRoute);
@override
void notify(NavigatorObserver observer) {
observer.didRemove(primaryRoute, secondaryRoute);
}
}
class _NavigatorReplaceObservation extends _NavigatorObservation {
_NavigatorReplaceObservation(
Route<dynamic> primaryRoute,
Route<dynamic> secondaryRoute
) : super(primaryRoute, secondaryRoute);
@override
void notify(NavigatorObserver observer) {
observer.didReplace(newRoute: primaryRoute, oldRoute: secondaryRoute);
}
}
/// The state for a [Navigator] widget. /// The state for a [Navigator] widget.
class NavigatorState extends State<Navigator> with TickerProviderStateMixin { class NavigatorState extends State<Navigator> with TickerProviderStateMixin {
final GlobalKey<OverlayState> _overlayKey = GlobalKey<OverlayState>(); final GlobalKey<OverlayState> _overlayKey = GlobalKey<OverlayState>();
List<_RouteEntry> _history = <_RouteEntry>[]; List<_RouteEntry> _history = <_RouteEntry>[];
final Queue<_NavigatorObservation> _observedRouteAdditions = Queue<_NavigatorObservation>();
final Queue<_NavigatorObservation> _observedRouteDeletions = Queue<_NavigatorObservation>();
/// The [FocusScopeNode] for the [FocusScope] that encloses the routes. /// The [FocusScopeNode] for the [FocusScope] that encloses the routes.
final FocusScopeNode focusScopeNode = FocusScopeNode(debugLabel: 'Navigator Scope'); final FocusScopeNode focusScopeNode = FocusScopeNode(debugLabel: 'Navigator Scope');
...@@ -2984,6 +3051,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin { ...@@ -2984,6 +3051,7 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin {
assert(rearrangeOverlay); assert(rearrangeOverlay);
entry.handleAdd( entry.handleAdd(
navigator: this, navigator: this,
previousPresent: _getRouteBefore(index - 1, _RouteEntry.isPresentPredicate)?.route,
); );
assert(entry.currentState == _RouteLifecycle.adding); assert(entry.currentState == _RouteLifecycle.adding);
continue; continue;
...@@ -2991,8 +3059,6 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin { ...@@ -2991,8 +3059,6 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin {
if (canRemoveOrAdd || next == null) { if (canRemoveOrAdd || next == null) {
entry.didAdd( entry.didAdd(
navigator: this, navigator: this,
previous: previous?.route,
previousPresent: _getRouteBefore(index - 1, _RouteEntry.isPresentPredicate)?.route,
isNewFirst: next == null isNewFirst: next == null
); );
assert(entry.currentState == _RouteLifecycle.idle); assert(entry.currentState == _RouteLifecycle.idle);
...@@ -3079,6 +3145,10 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin { ...@@ -3079,6 +3145,10 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin {
entry = previous; entry = previous;
previous = index > 0 ? _history[index - 1] : null; previous = index > 0 ? _history[index - 1] : null;
} }
// Informs navigator observers about route changes.
_flushObserverNotifications();
// Now that the list is clean, send the didChangeNext/didChangePrevious // Now that the list is clean, send the didChangeNext/didChangePrevious
// notifications. // notifications.
_flushRouteAnnouncement(); _flushRouteAnnouncement();
...@@ -3102,6 +3172,23 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin { ...@@ -3102,6 +3172,23 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin {
overlay?.rearrange(_allRouteOverlayEntries); overlay?.rearrange(_allRouteOverlayEntries);
} }
void _flushObserverNotifications() {
if (widget.observers.isEmpty) {
_observedRouteDeletions.clear();
_observedRouteAdditions.clear();
return;
}
while (_observedRouteAdditions.isNotEmpty) {
final _NavigatorObservation observation = _observedRouteAdditions.removeLast();
widget.observers.forEach(observation.notify);
}
while (_observedRouteDeletions.isNotEmpty) {
final _NavigatorObservation observation = _observedRouteDeletions.removeFirst();
widget.observers.forEach(observation.notify);
}
}
void _flushRouteAnnouncement() { void _flushRouteAnnouncement() {
int index = _history.length - 1; int index = _history.length - 1;
while (index >= 0) { while (index >= 0) {
......
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