Unverified Commit a4f5a587 authored by Dan Field's avatar Dan Field Committed by GitHub

Avoid retaining routes when subscriptions are cleared (#88310)

parent ddb8bfb7
......@@ -1733,6 +1733,19 @@ abstract class PopupRoute<T> extends ModalRoute<T> {
class RouteObserver<R extends Route<dynamic>> extends NavigatorObserver {
final Map<R, Set<RouteAware>> _listeners = <R, Set<RouteAware>>{};
/// Whether this observer is managing changes for the specified route.
///
/// If asserts are disabled, this method will throw an exception.
@visibleForTesting
bool debugObservingRoute(R route) {
late bool contained;
assert(() {
contained = _listeners.containsKey(route);
return true;
}());
return contained;
}
/// Subscribe [routeAware] to be informed about changes to [route].
///
/// Going forward, [routeAware] will be informed about qualifying changes
......@@ -1753,9 +1766,15 @@ class RouteObserver<R extends Route<dynamic>> extends NavigatorObserver {
/// subscribed to multiple types, this will unregister it (once) from each type.
void unsubscribe(RouteAware routeAware) {
assert(routeAware != null);
for (final R route in _listeners.keys) {
final List<R> routes = _listeners.keys.toList();
for (final R route in routes) {
final Set<RouteAware>? subscribers = _listeners[route];
subscribers?.remove(routeAware);
if (subscribers != null) {
subscribers.remove(routeAware);
if (subscribers.isEmpty) {
_listeners.remove(route);
}
}
}
}
......
......@@ -525,6 +525,33 @@ void main() {
expect(pageRouteAware.didPushCount, 2);
expect(pageRouteAware.didPopCount, 0);
});
test('releases reference to route when unsubscribed', () {
final RouteObserver<PageRoute<dynamic>> observer = RouteObserver<PageRoute<dynamic>>();
final MockRouteAware pageRouteAware = MockRouteAware();
final MockRouteAware page2RouteAware = MockRouteAware();
final MockPageRoute pageRoute = MockPageRoute();
final MockPageRoute nextPageRoute = MockPageRoute();
observer.subscribe(pageRouteAware, pageRoute);
observer.subscribe(pageRouteAware, nextPageRoute);
observer.subscribe(page2RouteAware, pageRoute);
observer.subscribe(page2RouteAware, nextPageRoute);
expect(pageRouteAware.didPushCount, 2);
expect(page2RouteAware.didPushCount, 2);
expect(observer.debugObservingRoute(pageRoute), true);
expect(observer.debugObservingRoute(nextPageRoute), true);
observer.unsubscribe(pageRouteAware);
expect(observer.debugObservingRoute(pageRoute), true);
expect(observer.debugObservingRoute(nextPageRoute), true);
observer.unsubscribe(page2RouteAware);
expect(observer.debugObservingRoute(pageRoute), false);
expect(observer.debugObservingRoute(nextPageRoute), false);
});
});
testWidgets('Can autofocus a TextField nested in a Focus in a route.', (WidgetTester tester) async {
......
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