要理解 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 的命令式导航方式在处理复杂导航逻辑、深度链接等需求时显得力不从心。
- 维护困难:随着应用复杂度的增加,手动管理路由栈可能变得难以维护。