要理解 Flutter 的 Navigator 1.0 工作原理,我们需要深入研究其背后的实现逻辑,并结合源代码进行详细解释。Navigator 1.0 的设计目标是管理应用中的页面导航,这通过维护一个路由栈(stack of routes)来实现。每个页面(route)都可以推入栈顶,或者从栈顶弹出。
1. Navigator 1.0 的核心概念
- Navigator:负责管理路由栈的核心类,它提供了推送(push)、弹出(pop)页面等功能。
- Route:表示导航栈中的一个页面,它是一个抽象类,有多个实现如
MaterialPageRoute。 - RouteStack:Navigator 内部维护的一个栈,用于管理路由的顺序和状态。
2. Navigator 1.0 的工作流程
Navigator 1.0 的核心是对路由栈的管理。当你调用 Navigator.push 时,一个新的路由被创建并推入栈顶;当你调用 Navigator.pop 时,栈顶的路由被移除。
2.1 Navigator.push 的实现
让我们从 Navigator.push 的实现开始看起:
dart
复制代码
static Future<T?> push<T extends Object?>(BuildContext context, Route<T> route) {
return Navigator.of(context).push(route);
}
Navigator.push 调用了 Navigator.of(context).push(route),让我们看看内部 NavigatorState 的 push 方法:
dart
复制代码
@override
Future<T?> push<T extends Object?>(Route<T> route) {
assert(!_debugLocked);
assert(() {
_debugLocked = true;
return true;
}());
_history.add(route);
route._navigator = this;
route.install();
if (route.isFirst) {
_first?.markNeedsBuild();
} else {
final ModalRoute<dynamic>? previousRoute = _history[_history.length - 2];
previousRoute?.didChangeNext(route);
}
route.didPush();
_cancelActivePointers();
route.didChange();
return route.popped;
}
这里发生了一系列操作:
_history.add(route):将新路由添加到路由栈中。route.install():安装路由,通常包括将页面挂载到 widget 树上。route.didPush():通知路由已经被推入栈顶。_cancelActivePointers():取消所有正在进行的触摸事件,以防止推送过程中发生意外事件。route.didChange():通知路由状态发生变化。
最终,push 方法返回一个 Future,该 Future 会在路由完成推入时完成。
2.2 Navigator.pop 的实现
类似地,Navigator.pop 的实现如下:
dart
复制代码
static bool pop<T extends Object?>(BuildContext context, [ T? result ]) {
return Navigator.of(context).maybePop(result);
}
Navigator.pop 实际上调用了 maybePop,这允许我们在弹出之前进行一些检查:
dart
复制代码
bool maybePop<T extends Object?>([ T? result ]) {
if (_history.isNotEmpty) {
final Route<T> route = _history.last as Route<T>;
final bool returnValue = route.willPop();
if (returnValue) {
pop<T>(result);
return true;
}
return false;
}
return false;
}
如果栈不为空,maybePop 会调用 route.willPop() 以确定是否应该弹出。如果确定要弹出,则会调用 pop:
dart
复制代码
void pop<T extends Object?>([ T? result ]) {
assert(!_debugLocked);
assert(() {
_debugLocked = true;
return true;
}());
final Route<dynamic>? route = _history.isNotEmpty ? _history.removeLast() : null;
if (route != null) {
route.didComplete(result);
route.dispose();
}
_cancelActivePointers();
route?.didChange();
}
这里的关键步骤是:
_history.removeLast():从路由栈中移除栈顶路由。route.didComplete(result):完成路由,并通过 Future 返回结果。route.dispose():释放与路由相关的资源。_cancelActivePointers():与推送时类似,取消正在进行的触摸事件。route?.didChange():通知剩余路由栈的栈顶路由状态已更改。
3. Route 的内部工作原理
Route 是 Navigator 管理的最基本的单位,Flutter 提供了多种类型的 Route,比如 MaterialPageRoute 和 CupertinoPageRoute。
3.1 Route 生命周期
Route 的生命周期包括几个关键阶段:
install():当 Route 被推入栈时调用,用于初始化与构建页面的相关工作。didPush():当 Route 被 Navigator 推入栈时调用,用于通知 Route 它现在在栈顶。willPop():在 Route 被弹出之前调用,以允许阻止弹出操作。didComplete():当 Route 被弹出并且导航完成时调用,用于清理资源并通知结果。dispose():当 Route 不再需要时调用,用于释放资源。
4. NavigatorState 和 InheritedWidget
Navigator 是一个 StatefulWidget,它的状态由 NavigatorState 来管理。Navigator.of(context) 实际上是在 widget 树中查找 Navigator 的 InheritedWidget,然后获取其状态。
dart
复制代码
static NavigatorState of(BuildContext context, { bool rootNavigator = false }) {
final NavigatorState? navigator = rootNavigator
? context.findRootAncestorStateOfType<NavigatorState>()
: context.findAncestorStateOfType<NavigatorState>();
assert(() {
if (navigator == null) {
throw FlutterError(
'Navigator operation requested with a context that does not include a Navigator.\n'
'The context used to push or pop routes from the Navigator must be that of a '
'widget that is a descendant of a Navigator widget.'
);
}
return true;
}());
return navigator!;
}
这里的 findAncestorStateOfType 和 findRootAncestorStateOfType 是 Flutter 用于在 widget 树中查找状态的方法,这允许 Navigator 访问到与当前上下文相关联的 NavigatorState。
5. Navigator 1.0 的优缺点
优点:
- 简单易用:Navigator 1.0 提供了简单直接的 API,使得页面导航非常直观。
- 适合简单应用:对于简单的页面切换和导航需求,Navigator 1.0 足够高效。
缺点:
- 灵活性不足:Navigator 1.0 的命令式导航方式在处理复杂导航逻辑、深度链接等需求时显得力不从心。
- 维护困难:随着应用复杂度的增加,手动管理路由栈可能变得难以维护。