Globally monitor routing stack changes

Lao Meng's introduction: Many times we need to monitor the changes of the routing stack, so that we can customize the routing stack and facilitate the analysis of exception logs.

Use RouteObserver to listen for changes in the routing stack, first add navigatorObservers to the MaterialApp component:

void main() {
  runApp(MyApp());
}

RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      ...
      navigatorObservers: [routeObserver],
      home: HomePage(),
    );
  }
}

The monitoring page settings are as follows:

class ARouteObserverDemo extends StatefulWidget {
  @override
  _RouteObserverDemoState createState() => _RouteObserverDemoState();
}

class _RouteObserverDemoState extends State<ARouteObserverDemo> with RouteAware {

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    routeObserver.subscribe(this, ModalRoute.of(context));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        alignment: Alignment.center,
        child: RaisedButton(
          child: Text('A RouteObserver'),
          onPressed: () {
            Navigator.of(context).pushNamed('/BRouteObserver');
          },
        ),
      ),
    );
  }

  @override
  void dispose() {
    super.dispose();
    routeObserver.unsubscribe(this);
  }

  @override
  void didPush() {
    final route = ModalRoute.of(context).settings.name;
    print('A-didPush route: $route');
  }

  @override
  void didPopNext() {
    final route = ModalRoute.of(context).settings.name;
    print('A-didPopNext route: $route');
  }

  @override
  void didPushNext() {
    final route = ModalRoute.of(context).settings.name;
    print('A-didPushNext route: $route');
  }

  @override
  void didPop() {
    final route = ModalRoute.of(context).settings.name;
    print('A-didPop route: $route');
  }

}

Where didPush, didPushNext, didPopNext, didPop are callbacks for routing stack changes.

Jump from page A to page ARouteObserverDemo, the log output is as follows:

flutter: A-didPush route: /ARouteObserver

Entering this page only calls didPush.

Jump from the ARouteObserverDemo page to the BRouteObserverDemo page (same as the ARouteObserverDemo page, with monitoring set up), the log output is as follows:

flutter: A-didPushNext route: /ARouteObserver
flutter: B-didPush route: /BRouteObserver

The didPushNext of the ARouteObserverDemo page is called first, and then the didPush of the BRouteObserverDemo page is called.

Execute pop from the BRouteObserverDemo page to return to the ARouteObserverDemo page, and the log output is as follows:

flutter: A-didPopNext route: /ARouteObserver
flutter: B-didPop route: /BRouteObserver

The didPopNext of the ARouteObserverDemo page is called first, and then the didPop of the BRouteObserverDemo page is called.

The above case is only a routing stack change at the page level. If you want to know how the routing stack change of the entire application is handled?

One way is to write a base class that listens to the routing stack and that all pages inherit from this base class. This method is very intrusive to the source code.

Another way is to customize RouteObserver, inherit RouteObserver and override the methods in it:

class MyRouteObserver<R extends Route<dynamic>> extends RouteObserver<R> {
  @override
  void didPush(Route route, Route previousRoute) {
    super.didPush(route, previousRoute);
    print('didPush route: $route,previousRoute:$previousRoute');
  }

  @override
  void didPop(Route route, Route previousRoute) {
    super.didPop(route, previousRoute);
    print('didPop route: $route,previousRoute:$previousRoute');
  }

  @override
  void didReplace({Route newRoute, Route oldRoute}) {
    super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
    print('didReplace newRoute: $newRoute,oldRoute:$oldRoute');
  }

  @override
  void didRemove(Route route, Route previousRoute) {
    super.didRemove(route, previousRoute);
    print('didRemove route: $route,previousRoute:$previousRoute');
  }

  @override
  void didStartUserGesture(Route route, Route previousRoute) {
    super.didStartUserGesture(route, previousRoute);
    print('didStartUserGesture route: $route,previousRoute:$previousRoute');
  }

  @override
  void didStopUserGesture() {
    super.didStopUserGesture();
    print('didStopUserGesture');
  }
}

use:

void main() {
  runApp(MyApp());
}

MyRouteObserver<PageRoute> myRouteObserver = MyRouteObserver<PageRoute>();

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      navigatorObservers: [myRouteObserver],
      initialRoute: '/A',
      home: APage(),
    );
  }
}

At this point, jump from page A to page B, and the log output is as follows:

flutter: didPush route: MaterialPageRoute<dynamic>(RouteSettings("/B", from A), animation: AnimationController#6d429(▶ 0.000; for MaterialPageRoute<dynamic>(/B))),previousRoute:MaterialPageRoute<dynamic>(RouteSettings("/A", null), animation: AnimationController#e60f7(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/A)))

comminicate

comminicate

Lao Meng Flutter blog (330 control usage + practical entry series articles): http://laomengit.com

Welcome to join the Flutter exchange group (WeChat: laomengit), pay attention to the public account [Lao Meng Flutter]:

Tags: Flutter

Posted by sgtbash on Tue, 17 May 2022 08:34:57 +0300