navigatorObservers
是什么
在 Flutter 中,MaterialApp
或 CupertinoApp
都有一个参数:
MaterialApp(
navigatorObservers: [/* 一组 NavigatorObserver */],
)
作用:它允许你监听 Navigator
(路由栈管理器)的各种路由变化,比如:
- 页面
push
(进入) - 页面
pop
(退出) - 页面
replace
(替换)
要求传入的类型:final List<NavigatorObserver> navigatorObservers;
- 它是一个
NavigatorObserver
的列表,你可以放多个,比如RouteObserver
、自定义的NavigatorObserver
。
NavigatorObserver
基类
Flutter 提供了一个基类 NavigatorObserver
,定义了一些回调方法。只要页面路由发生变化,就能在这里监听。
/// An interface for observing the behavior of a [Navigator].
class NavigatorObserver {
/// The navigator that the observer is observing, if any.
NavigatorState? get navigator => _navigators[this];
static final Expando<NavigatorState> _navigators = Expando<NavigatorState>();
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {}
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {}
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {}
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {}
void didChangeTop(Route<dynamic> topRoute, Route<dynamic>? previousTopRoute) {}
void didStartUserGesture(Route<dynamic> route, Route<dynamic>? previousRoute) {}
void didStopUserGesture() {}
}
回调函数 | 触发时机 | 常见应用场景 |
---|---|---|
didPush |
页面 push 进入 | 统计进入次数、初始化数据 |
didPop |
页面 pop 退出 | 停留时长统计、资源释放 |
didRemove |
路由被 直接移除 | 强制清理路由、登出处理 |
didReplace |
路由被 替换 | 登录→首页、Splash→主页面 |
didChangeTop |
栈顶路由变化 | 页面切换监听、控制资源 |
didStartUserGesture |
手势导航开始 | 暂停动画、禁用交互 |
didStopUserGesture |
手势导航结束 | 恢复动画、继续逻辑 |
Route<dynamic> route
:新加入的路由
Route<dynamic>? previousRoute
:之前处于栈顶的路由(可能是 null
,如果是第一个页面)
Route<dynamic>? newRoute
:替换后的新路由
Route<dynamic>? oldRoute
:被替换掉的路由
didPop
与didRemove
区别:
didPop
是 用户或系统触发的页面退出didRemove
是 代码直接删除了某个路由(不会触发页面退出动画)- 当调用
Navigator.removeRoute
或者Navigator.removeRouteBelow
等方法 直接移除路由 时触发。
- 当调用
didReplace
:当调用 Navigator.pushReplacement
或 Navigator.replace
时触发。
didChangeTop
:当 栈顶路由发生变化 时触发(无论是 push
、pop
、replace
)。
案例
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
navigatorObservers: [MyNavigatorObserver()], // 注册自定义观察器
routes: {'/': (_) => FirstPage(), '/second': (_) => SecondPage()},
),
);
}
// 自定义全局路由观察器
class MyNavigatorObserver extends NavigatorObserver {
// didPush: 处理路由推送事件
@override
void didPush(Route route, Route? previousRoute) {
debugPrint(
"didPush: ${route.settings.name}, from: ${previousRoute?.settings.name}",
);
}
// didPop: 处理路由弹出事件
@override
void didPop(Route route, Route? previousRoute) {
debugPrint(
"didPop: ${route.settings.name}, back to: ${previousRoute?.settings.name}",
);
}
// didRemove: 处理路由移除事件
@override
void didRemove(Route route, Route? previousRoute) {
debugPrint("didRemove: ${route.settings.name}");
}
// didReplace: 处理路由替换事件
@override
void didReplace({Route? newRoute, Route? oldRoute}) {
debugPrint(
"didReplace: ${oldRoute?.settings.name} -> ${newRoute?.settings.name}",
);
}
// didChangeTop: 处理路由栈顶变化事件
@override
void didChangeTop(Route topRoute, Route? previousTopRoute) {
debugPrint(
"didChangeTop: ${previousTopRoute?.settings.name} -> ${topRoute.settings.name}",
);
}
}
class FirstPage extends StatelessWidget {
const FirstPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("First Page")),
body: Center(
child: ElevatedButton(
child: Text("Go to Second"),
onPressed: () => Navigator.pushNamed(context, '/second'),
),
),
);
}
}
class SecondPage extends StatelessWidget {
const SecondPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Second Page")),
body: Center(
child: ElevatedButton(
child: Text("Back"),
onPressed: () => Navigator.pop(context),
),
),
);
}
}
// 日志:
I/flutter (12161): didPush: /second, from: /
I/flutter (12161): didChangeTop: / -> /second
W/WindowOnBackDispatcher(12161): OnBackInvokedCallback is not enabled for the application.
W/WindowOnBackDispatcher(12161): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
I/flutter (12161): didPop: /second, back to: /
I/flutter (12161): didChangeTop: /second -> /
Route 类
在 Flutter 里,Route
就是对一个页面(screen/page)的抽象表示。
abstract class Route<T> extends _RoutePlaceholder
比如当 Navigator.push(...)
时,本质上就是往路由栈里 压入一个新的 Route 对象。
常见的 Route 类型:
MaterialPageRoute<T>
:最常用的路由,带有 Material 动画效果(安卓风格)。Navigator.push( context, MaterialPageRoute(builder: (_) => MyPage()), );
CupertinoPageRoute<T>
:iOS 风格的路由(右滑返回)。PageRouteBuilder<T>
:自定义路由动画,可以自己定义transitionBuilder
。ModalRoute<T>
:抽象类,所有模态(覆盖式)页面路由的基类。MaterialPageRoute
就是继承自ModalRoute
。PopupRoute<T>
:比如DialogRoute
、PopupMenuRoute
。
总结: Route
= 页面容器,它定义了页面的生命周期、动画、是否全屏、返回值等。
RouteObserver 类
class RouteObserver<R extends Route<dynamic>> extends NavigatorObserver {
final Map<R, Set<RouteAware>> _listeners = <R, Set<RouteAware>>{};
RouteObserver<R extends Route<dynamic>>
是 Flutter 提供的一个 导航事件监听工具类,它继承自 NavigatorObserver
。由于继承了NavigatorObserver
,所有它监听 Navigator
(路由栈管理器)的各种路由变化。
- 页面
push
(进入) - 页面
pop
(退出) - 页面
replace
(替换)
此外,它在 NavigatorObserver
的基础上,扩展了 订阅/取消订阅 机制,方便某些 Widget(通常是 StatefulWidget
)在路由变化时收到通知。
class RouteObserver<R extends Route<dynamic>> extends NavigatorObserver {
final Map<R, Set<RouteAware>> _listeners = <R, Set<RouteAware>>{};
void subscribe(RouteAware routeAware, R route) {
// 订阅某个路由
}
void unsubscribe(RouteAware routeAware) {
// 取消订阅
}
@override
void didPush(Route route, Route? previousRoute) {
// 通知监听者
}
@override
void didPop(Route route, Route? previousRoute) {
// 通知监听者
}
}
案例:使用RouteObserver
RouteObserver
本身只有全局回调,你需要手动if (route.settings.name == ...)
判断是哪一个页面。- 当页面越来越多时,你会写很多
if else
来判断route.settings.name
。 - 此外,这么写代码耦合度高,所有逻辑都堆在
LoggingRouteObserver
里。
import 'package:flutter/material.dart';
// 全局 RouteObserver
// final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
/// 自定义 LoggingRouteObserver
class LoggingRouteObserver extends RouteObserver<PageRoute<dynamic>> {
@override
void didPush(Route route, Route? previousRoute) {
super.didPush(route, previousRoute);
debugPrint("didPush: ${route.settings.name}");
// 判断逻辑
if (route.settings.name == '/second') {
debugPrint("👉 进入 SecondPage,做一些逻辑");
} else if (route.settings.name == '/third') {
debugPrint("👉 进入 ThirdPage,加载第三页数据");
}
}
@override
void didPop(Route route, Route? previousRoute) {
super.didPop(route, previousRoute);
debugPrint("didPop: ${route.settings.name}");
if (route.settings.name == '/second') {
debugPrint("👉 离开 SecondPage,清理资源");
} else if (route.settings.name == '/third') {
debugPrint("👉 离开 ThirdPage,保存草稿");
}
}
}
void main() {
runApp(
MaterialApp(
navigatorObservers: [LoggingRouteObserver()], // 注册自定义的 RouteObserver
routes: {
'/': (_) => FirstPage(),
'/second': (_) => SecondPage(),
'/third': (_) => ThirdPage(),
},
),
);
}
class FirstPage extends StatelessWidget {
const FirstPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("First Page")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
child: Text("Go to Second"),
onPressed: () => Navigator.pushNamed(context, '/second'),
),
ElevatedButton(
child: Text("Go to Third"),
onPressed: () => Navigator.pushNamed(context, '/third'),
),
],
),
),
);
}
}
class SecondPage extends StatelessWidget {
const SecondPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Second Page")),
body: Center(
child: ElevatedButton(
child: Text("Go to Third"),
onPressed: () => Navigator.pushNamed(context, '/third'),
),
),
);
}
}
class ThirdPage extends StatelessWidget {
const ThirdPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Third Page")),
body: Center(
child: ElevatedButton(
child: Text("Back"),
onPressed: () => Navigator.pop(context),
),
),
);
}
}
日志如下:
I/flutter (12420): didPush: /
I/flutter (12420): didPush: /second
I/flutter (12420): 👉 进入 SecondPage,做一些逻辑
W/WindowOnBackDispatcher(12420): OnBackInvokedCallback is not enabled for the application.
W/WindowOnBackDispatcher(12420): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
I/flutter (12420): didPush: /third
I/flutter (12420): 👉 进入 ThirdPage,加载第三页数据
I/flutter (12420): didPop: /third
I/flutter (12420): 👉 离开 ThirdPage,保存草稿
I/flutter (12420): didPush: /third
I/flutter (12420): 👉 进入 ThirdPage,加载第三页数据
I/flutter (12420): didPop: /third
I/flutter (12420): 👉 离开 ThirdPage,保存草稿
I/flutter (12420): didPop: /second
I/flutter (12420): 👉 离开 SecondPage,清理资源
I/flutter (12420): didPush: /third
I/flutter (12420): 👉 进入 ThirdPage,加载第三页数据
W/WindowOnBackDispatcher(12420): OnBackInvokedCallback is not enabled for the application.
W/WindowOnBackDispatcher(12420): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
I/flutter (12420): didPop: /third
I/flutter (12420): 👉 离开 ThirdPage,保存草稿
RouteAware
接口
这是和 RouteObserver
搭配使用的接口,页面 State
可以实现它来感知路由生命周期:
abstract mixin class RouteAware {
void didPush(); // 当前页面 被 push 进来 时调用(即当前页面进入导航栈并显示)。
void didPop(); // 当前页面 被 pop 出去 时调用(即当前页面被销毁)。
void didPopNext(); // 当 新的页面 push 进来覆盖当前页面 时调用(当前页面进入“不可见”状态)。
void didPushNext(); // 当 上层页面被 pop 掉后,当前页面重新可见时调用。
}
假设我们有 PageA → PageB → PageC 这三页。
- 开始页面:
PageA
PageA.didPush()
(A 第一次显示)
- 从
PageA
→PageB
PageA.didPushNext()
(A 被覆盖,不可见)PageB.didPush()
(B 显示)
- 从
PageB
→PageC
PageB.didPushNext()
(B 被覆盖,不可见)PageC.didPush()
(C 显示)
PageC
被 Pop 回到PageB
PageC.didPop()
(C 被销毁)PageB.didPopNext()
(B 再次可见)
PageB
被 Pop 回到PageA
PageB.didPop()
(B 被销毁)PageA.didPopNext()
(A 再次可见)
NavigatorObserver VS. RouteAware
NavigatorObserver
的特点
是全局的:你在 MaterialApp.navigatorObservers
里配置,所有路由变化都会经过它。
回调方法:didPush
、didPop
、didRemove
、didReplace
、didChangeTop
等。
问题:
- 你在这里拿到的是 所有页面的路由变化。
- 如果你只想让某个页面知道「自己什么时候被覆盖、什么时候重新显示」,你就得写一堆逻辑去匹配
route
,会比较麻烦。
RouteAware
的特点
是局部的:页面(State
)自己 with RouteAware
,再手动订阅 RouteObserver
,就能收到自己的路由生命周期。
回调方法:didPush
、didPop
、didPushNext
、didPopNext
。
好处:
- 页面只关心自己的可见性变化,不用在全局的
NavigatorObserver
里去做if (route.settings.name == "XXX")
这种判断。 - 封装性更好:逻辑留在页面内部,减少耦合。
比较
特点 | NavigatorObserver | RouteAware |
---|---|---|
作用范围 | 全局,监听所有路由变化 | 局部,页面自己订阅自己 |
回调对象 | 所有路由(需要自己过滤) | 当前页面本身 |
使用复杂度 | 简单监听:适合统计、日志 | 页面内逻辑:更方便 |
应用场景 | 全局埋点、导航统计、统一处理 | 单页面生命周期(视频暂停/恢复、定时器管理) |
案例1:使用RouteObserver
+RouteAware
import 'package:flutter/material.dart';
/// 这个实例需要被:1) 注册到 navigatorObservers;2) 在页面中订阅
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
void main() {
runApp(
MaterialApp(
navigatorObservers: [routeObserver], // 一定要注册这个实例
routes: {
'/': (_) => FirstPage(),
'/second': (_) => SecondPage(),
'/third': (_) => ThirdPage(),
},
),
);
}
class FirstPage extends StatelessWidget {
const FirstPage({super.key});
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text("First Page")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
child: const Text("Go to Second"),
onPressed: () => Navigator.pushNamed(context, '/second'),
),
ElevatedButton(
child: const Text("Go to Third"),
onPressed: () => Navigator.pushNamed(context, '/third'),
),
],
),
),
);
}
class SecondPage extends StatefulWidget {
const SecondPage({super.key});
@override
State<SecondPage> createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> with RouteAware {
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 用“同一个” routeObserver 订阅当前 PageRoute
// ModalRoute.of(context): 获取当前路由
// as PageRoute: 类型转换
// void subscribe(RouteAware routeAware, R route)
routeObserver.subscribe(this, ModalRoute.of(context)! as PageRoute);
}
@override
void dispose() {
// 销毁的时候取消订阅
routeObserver.unsubscribe(this);
super.dispose();
}
// 当前页面被 push 到导航栈
@override
void didPush() => debugPrint("SecondPage didPush");
// 当前页面被 pop 出导航栈
@override
void didPop() => debugPrint("SecondPage didPop");
// 当前页面被覆盖(即将进入下一个页面)
@override
void didPushNext() => debugPrint("SecondPage 被覆盖(didPushNext)");
// 当前页面重新显示(从下一个页面返回)
@override
void didPopNext() => debugPrint("返回到 SecondPage(didPopNext)");
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text("Second Page")),
body: Center(
child: ElevatedButton(
child: const Text("Go to Third"),
onPressed: () => Navigator.pushNamed(context, '/third'),
),
),
);
}
class ThirdPage extends StatefulWidget {
const ThirdPage({super.key});
@override
State<ThirdPage> createState() => _ThirdPageState();
}
class _ThirdPageState extends State<ThirdPage> with RouteAware {
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 用“同一个” routeObserver 订阅当前 PageRoute
// ModalRoute.of(context): 获取当前路由
// as PageRoute: 类型转换
// void subscribe(RouteAware routeAware, R route)
routeObserver.subscribe(this, ModalRoute.of(context)! as PageRoute);
}
@override
void dispose() {
// 销毁的时候取消订阅
routeObserver.unsubscribe(this);
super.dispose();
}
// 当前页面被 push 到导航栈
@override
void didPush() => debugPrint("ThirdPage didPush");
@override
void didPop() => debugPrint("ThirdPage didPop");
@override
void didPushNext() => debugPrint("ThirdPage 被覆盖(didPushNext)");
@override
void didPopNext() => debugPrint("返回到 ThirdPage(didPopNext)");
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text("Third Page")),
body: Center(
child: ElevatedButton(
child: const Text("Back"),
onPressed: () => Navigator.pop(context),
),
),
);
}
以下是日志:
// 日志
I/flutter (12638): SecondPage didPush
W/WindowOnBackDispatcher(12638): OnBackInvokedCallback is not enabled for the application.
W/WindowOnBackDispatcher(12638): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
I/flutter (12638): SecondPage 被覆盖(didPushNext)
I/flutter (12638): ThirdPage didPush
I/flutter (12638): 返回到 SecondPage(didPopNext)
I/flutter (12638): ThirdPage didPop
I/flutter (12638): SecondPage didPop
案例2:全局回调 + 转发给 RouteAware
在上面这个案例中,RouteObserver
并没有重写方法,所有无法使用NavigatorObserver
的回调函数。
所有我们可以自定义一个类AppRouteObserver
,然后继承RouteObserver
。
接着在注册到navigatorObservers
,这样就可以实现RouteAware
和NavigatorObserver
的特性。
import 'package:flutter/material.dart';
/// 全局单例:自定义的 RouteObserver(同时承担全局回调 + RouteAware 分发)
final AppRouteObserver appRouteObserver = AppRouteObserver();
class AppRouteObserver extends RouteObserver<PageRoute<dynamic>> {
// 当有 route 被 push 时,First: 调用 super,确保 RouteObserver 通知订阅者
// Second: 在这里写你的“全局”逻辑(埋点 / 统一处理)
@override
void didPush(Route route, Route? previousRoute) {
super.didPush(route, previousRoute); // <<< 必须,负责触发 RouteAware 回调
debugPrint("-------------------------------------------------------");
debugPrint(
'AppRouteObserver.didPush: ${route.settings.name}, from: ${previousRoute?.settings.name}',
);
// 全局逻辑示例:针对某个路由做特殊处理
if (route.settings.name == '/second') {
debugPrint('🔔 全局处理:SecondPage 进入(例如埋点/预加载)');
}
debugPrint("-------------------------------------------------------");
}
@override
void didPop(Route route, Route? previousRoute) {
super.didPop(route, previousRoute);
debugPrint("-------------------------------------------------------");
debugPrint(
'AppRouteObserver.didPop: ${route.settings.name}, back to: ${previousRoute?.settings.name}',
);
if (route.settings.name == '/third') {
debugPrint('🔔 全局处理:ThirdPage 离开(例如保存草稿)');
}
debugPrint("-------------------------------------------------------");
}
// 其它回调也同理(示例省略重复)
@override
void didChangeTop(Route<dynamic> topRoute, Route<dynamic>? previousTopRoute) {
super.didChangeTop(topRoute, previousTopRoute);
debugPrint("-------------------------------------------------------");
debugPrint(
'AppRouteObserver.didChange: ${previousTopRoute?.settings.name} -> ${topRoute.settings.name}',
);
debugPrint("-------------------------------------------------------");
}
}
void main() {
runApp(
MaterialApp(
navigatorObservers: [appRouteObserver], // 注册同一个实例
routes: {
'/': (_) => FirstPage(),
'/second': (_) => SecondPage(),
'/third': (_) => ThirdPage(),
},
),
);
}
class FirstPage extends StatelessWidget {
const FirstPage({super.key});
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text("First Page")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => Navigator.pushNamed(context, '/second'),
child: const Text('Go to Second'),
),
ElevatedButton(
onPressed: () => Navigator.pushNamed(context, '/third'),
child: const Text('Go to Third'),
),
],
),
),
);
}
/// SecondPage 使用 RouteAware:局部页面逻辑放在页面内部
class SecondPage extends StatefulWidget {
const SecondPage({super.key});
@override
State<SecondPage> createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> with RouteAware {
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 订阅“同一个被注册到 navigatorObservers 的实例”
appRouteObserver.subscribe(this, ModalRoute.of(context)! as PageRoute);
}
@override
void dispose() {
appRouteObserver.unsubscribe(this);
super.dispose();
}
// RouteAware 回调:页面自己负责播放/暂停/刷新等逻辑
@override
void didPush() => debugPrint('SecondPage: didPush (页面进入)');
@override
void didPop() => debugPrint('SecondPage: didPop (页面退出)');
@override
void didPushNext() => debugPrint('SecondPage: didPushNext (被覆盖)');
@override
void didPopNext() => debugPrint('SecondPage: didPopNext (下一个页面退出,自己可见)');
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text('Second Page')),
body: Center(
child: ElevatedButton(
onPressed: () => Navigator.pushNamed(context, '/third'),
child: const Text('Go to Third'),
),
),
);
}
class ThirdPage extends StatefulWidget {
const ThirdPage({super.key});
@override
State<ThirdPage> createState() => _ThirdPageState();
}
class _ThirdPageState extends State<ThirdPage> with RouteAware {
@override
void didChangeDependencies() {
super.didChangeDependencies();
appRouteObserver.subscribe(this, ModalRoute.of(context)! as PageRoute);
}
@override
void dispose() {
appRouteObserver.unsubscribe(this);
super.dispose();
}
@override
void didPush() => debugPrint('ThirdPage: didPush');
@override
void didPop() => debugPrint('ThirdPage: didPop');
@override
void didPushNext() => debugPrint('ThirdPage: didPushNext');
@override
void didPopNext() => debugPrint('ThirdPage: didPopNext');
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text('Third Page')),
body: Center(
child: ElevatedButton(
onPressed: () => Navigator.pop(context),
child: const Text('Back'),
),
),
);
}
以下是日志:
Restarted application in 1,559ms.
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): AppRouteObserver.didPush: /, from: null
2
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): AppRouteObserver.didChange: null -> /
2
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): AppRouteObserver.didPush: /second, from: /
I/flutter (13167): 🔔 全局处理:SecondPage 进入(例如埋点/预加载)
2
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): AppRouteObserver.didChange: / -> /second
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): SecondPage: didPush (页面进入)
W/WindowOnBackDispatcher(13167): OnBackInvokedCallback is not enabled for the application.
W/WindowOnBackDispatcher(13167): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
I/flutter (13167): SecondPage: didPushNext (被覆盖)
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): AppRouteObserver.didPush: /third, from: /second
2
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): AppRouteObserver.didChange: /second -> /third
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): ThirdPage: didPush
I/flutter (13167): SecondPage: didPopNext (下一个页面退出,自己可见)
I/flutter (13167): ThirdPage: didPop
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): AppRouteObserver.didPop: /third, back to: /second
I/flutter (13167): 🔔 全局处理:ThirdPage 离开(例如保存草稿)
2
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): AppRouteObserver.didChange: /third -> /second
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): SecondPage: didPop (页面退出)
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): AppRouteObserver.didPop: /second, back to: /
2
I/flutter (13167): -------------------------------------------------------
I/flutter (13167): AppRouteObserver.didChange: /second -> /
I/flutter (13167): -------------------------------------------------------
案例3:同时注册两个 observer
如果你想把“全局逻辑”写在一个独立的 MyNavigatorObserver
类里,同时又想使用 RouteAware
,也可以 把两个实例都注册到 navigatorObservers
。但订阅时必须订阅那个真正的 RouteObserver
实例(不能新建一个没有注册的实例)。
final RouteObserver<PageRoute> globalRouteObserver = RouteObserver<PageRoute>();
final MyNavigatorObserver myNavObserver = MyNavigatorObserver();
class MyNavigatorObserver extends NavigatorObserver {
@override
void didPush(Route route, Route? previousRoute) {
debugPrint('MyNavigatorObserver didPush: ${route.settings.name}');
// 注意:此类不是 RouteObserver,不能替代 RouteObserver 的 subscribe/分发机制
}
}
void main() {
runApp(MaterialApp(
// 注意:同时注册两个 observer
navigatorObservers: [myNavObserver, globalRouteObserver],
routes: {
'/': (_) => FirstPage(),
'/second': (_) => SecondPage(),
'/third': (_) => ThirdPage(),
},
));
}
// 页面订阅必须使用 globalRouteObserver(就是上面注册的实例)
class SecondPage extends StatefulWidget { /* ... same as above ... */ }
class _SecondPageState extends State<SecondPage> with RouteAware {
@override
void didChangeDependencies() {
super.didChangeDependencies();
globalRouteObserver.subscribe(this, ModalRoute.of(context)! as PageRoute);
}
@override
void dispose() {
globalRouteObserver.unsubscribe(this);
super.dispose();
}
// ...
}