Repository: flutter
Issue: [Bug?] in didPopNext and didPop call order
Labels: framework,f: routes,has reproducible steps,P2,found in release: 3.3,found in release: 3.7,team-framework,triaged-framework

Hi, 

The following code is the logic from `RouteObserver` which calls any `RouteAware` widgets when a route is popped.
```dart
@override
  void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
    if (route is R && previousRoute is R) {
      final List<RouteAware> previousSubscribers = _listeners[previousRoute]?.toList();

      if (previousSubscribers != null) {
        for (RouteAware routeAware in previousSubscribers) {
          routeAware.didPopNext();
        }
      }

      final List<RouteAware> subscribers = _listeners[route]?.toList();

      if (subscribers != null) {
        for (RouteAware routeAware in subscribers) {
          routeAware.didPop();
        }
      }
    }
  }
```

In my app I have a feature flag that I turn on/off based on the page that I'm showing, and rely on the `RouteAware` callbacks. I wrap all the pages where I want to enable the feature flag in a `RouteAware` widget, which turns the global flag to `TRUE` if `didPush(starting the page)`/`didPopNext(coming back from the next page)`, or `FALSE` if `didPop(closing the page)`/`didPushNext(going to the next page)`. 

The problem comes when I have two sequential pages that turn ON the feature flag and the second one navigates back to the first one, because the logic calls `previousRouteSubscribers` first, so, `didPopNext` on page A is called first, and `didPop` on page B is called second, which turns my flag `TRUE` and then `FALSE`, which is not what I want. My first instinct would be that you first want to call the callbacks registered by page B because we are disposing of it, and want to clean it first, and then the callbacks for page A, because we are going to it. Is this the intended order, or should there be a mechanism to chose what order in which you want the callback fired, or should I not rely on this api for what I'm trying to achieve?

Minimal reproducible example:

```dart
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

final routeObserver = RouteObserver<PageRoute>();

ValueNotifier<bool> isFeatureFlagEnabled = ValueNotifier(false);

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorObservers: [routeObserver],
      title: 'Flutter Demo',
      theme: ThemeData(
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: Page1(),
    );
  }
}

// Feature Flag ENABLED
class Page3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FeatureFlagWidget(
      child: Scaffold(
        appBar: AppBar(
          leading: BackButton(),
          title: Text('Page 3'),
          centerTitle: true,
        ),
        body: SafeArea(
            child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              AnimatedBuilder(
                animation: isFeatureFlagEnabled,
                builder: (BuildContext context, Widget child) {
                  return Text('Feature flag is enabled is '
                      '${isFeatureFlagEnabled.value.toString().toUpperCase()}');
                },
              ),
            ],
          ),
        )),
      ),
    );
  }
}

// Feature Flag NOT ENABLED
class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: BackButton(),
        title: Text('Page 1'),
        centerTitle: true,
      ),
      body: SafeArea(
          child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            AnimatedBuilder(
              animation: isFeatureFlagEnabled,
              builder: (BuildContext context, Widget child) {
                return Text('Feature flag is enabled is '
                    '${isFeatureFlagEnabled.value.toString().toUpperCase()}');
              },
            ),
            RaisedButton(
              onPressed: () {
                _pushMaterialPageRoute(context, Page2());
              },
              child: Text('Go to Page 2'),
            ),
          ],
        ),
      )),
    );
  }
}

// Feature Flag ENABLED
class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print("hello");
    return FeatureFlagWidget(
      child: Scaffold(
        appBar: AppBar(
          leading: BackButton(),
          title: Text('Page 2'),
          centerTitle: true,
        ),
        body: SafeArea(
            child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              AnimatedBuilder(
                animation: isFeatureFlagEnabled,
                builder: (BuildContext context, Widget child) {
                  return Text('Feature flag is enabled is '
                      '${isFeatureFlagEnabled.value.toString().toUpperCase()}');
                },
              ),
              RaisedButton(
                onPressed: () {
                  _pushMaterialPageRoute(context, Page3());
                },
                child: Text('Go to Page 3'),
              ),
            ],
          ),
        )),
      ),
    );
  }
}

class FeatureFlagWidget extends StatefulWidget {
  FeatureFlagWidget({this.child});

  final Widget child;

  @override
  _FeatureFlagWidgetState createState() => _FeatureFlagWidgetState();
}

class _FeatureFlagWidgetState extends State<FeatureFlagWidget> with RouteAware {
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    routeObserver.subscribe(this, ModalRoute.of(context));
  }

  @override
  void dispose() {
    routeObserver.unsubscribe(this);
    super.dispose();
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  void didPush() {
    print("didPush");
    // To avoid updating while widget is building
    Future.microtask(() {
      isFeatureFlagEnabled.value = true;
    });
  }

  @override
  void didPopNext() {
    print("didPopNext");
    isFeatureFlagEnabled.value = true;
  }

  @override
  void didPop() {
    print("didPop");
    isFeatureFlagEnabled.value = false;
  }

  @override
  void didPushNext() {
    print("didPushNext");
    isFeatureFlagEnabled.value = false;
  }

  @override
  Widget build(BuildContext context) => widget.child;
}

void _pushMaterialPageRoute(BuildContext context, Widget child) =>
    Navigator.of(context).push(
        MaterialPageRoute<void>(builder: (BuildContext context) => child));
```

When you run the example, see the when you go forward Page 1 -> Page 2 -> Page 3, feature flag is enabled on Page 2 and Page 3, but when you come back from Page 3 to Page 2, the flag is false. That is because `didPopNext(of Page 2)` got called before `didPop(of Page 3)`. 

Thanks!