Flutter路由源码
参考来源:
从Navigator的push方法去探索源码,并结合GetX跳转进行分析。
push代码速看
NavigatorState对象检索
Navigator.push是一个静态方法,使得你可以在任何地方进行调用,其内部通过of方法在Element树(BuildContext是 Element的抽象类)中进行向上搜索。我们看下Navigator.of方法:
dart
static NavigatorState of(
BuildContext context, {
bool rootNavigator = false,
bool nullOk = false,
}) {
final NavigatorState navigator = rootNavigator
? context.rootAncestorStateOfType(const TypeMatcher<NavigatorState>())
: context.ancestorStateOfType(const TypeMatcher<NavigatorState>());
return navigator;
}
在GetX的NavigatorState检索为
dart
// global方法通过GlobalKey返回NavigatorState
// eg: global(id).currentState
GlobalKey<NavigatorState> global(int? k) {
GlobalKey<NavigatorState> newKey;
// ...
return newKey;
}
主要通过rootNavigator变量判断是否要检索根部Navigator,rootAncestorStateOfType向上查找最根部匹配类型对象,ancestorStateOfType向上查找最近的匹配类型对象。从这个方法我们也可以知道Navigator.of方法查找的不是Navigator而是NavigatorState,这个也比较容易理解,Navigator是一个StatefulWidget,具体的逻辑都在它的State对象当中。
push的实现
dart
/// 推出一个路由
void _pushEntry(_RouteEntry entry) {
// ...
_history.add(entry);
// 主要看刷新历史并更新这个方法
_flushHistoryUpdates();
// ...
_afterNavigation(entry.route);
}
void _flushHistoryUpdates({bool rearrangeOverlay = true}) {
assert(_debugLocked && !_debugUpdatingPage);
_flushingHistory = true;
// 清理列表,向更改的路由发送更新。
// 值得注意的是,我们不会将didChangePrevious/didChangeNext更新发送给那些此时没有更改的路由
// 因为我们还不确定在一天结束时路由将是什么(有些可能会被处理)。
/// _history是Navigator所维护的界面栈,是一个普通的List -> (Iterable<_RouteEntry>)
int index = _history.length - 1;
_RouteEntry? next;
// 取原本在栈顶的route,因为_history是一个普通的List,所以栈顶就是最后一个元素
_RouteEntry? entry = _history[index];
_RouteEntry? previous = index > 0 ? _history[index - 1] : null;
bool canRemoveOrAdd = false; // Whether there is a fully opaque route on top to silently remove or add route underneath.
Route<dynamic>? poppedRoute; // The route that should trigger didPopNext on the top active route.
bool seenTopActiveRoute = false; // Whether we've seen the route that would get didPopNext.
final List<_RouteEntry> toBeDisposed = <_RouteEntry>[];
while (index >= 0) {
switch (entry!.currentState) {
case _RouteLifecycle.add:
assert(rearrangeOverlay);
entry.handleAdd(
navigator: this,
previousPresent: _getRouteBefore(index - 1, _RouteEntry.isPresentPredicate)?.route,
);
assert(entry.currentState == _RouteLifecycle.adding);
continue;
case _RouteLifecycle.adding:
if (canRemoveOrAdd || next == null) {
entry.didAdd(
navigator: this,
isNewFirst: next == null,
);
assert(entry.currentState == _RouteLifecycle.idle);
continue;
}
case _RouteLifecycle.push:
case _RouteLifecycle.pushReplace:
case _RouteLifecycle.replace:
assert(rearrangeOverlay);
entry.handlePush(
navigator: this,
previous: previous?.route,
previousPresent: _getRouteBefore(index - 1, _RouteEntry.isPresentPredicate)?.route,
isNewFirst: next == null,
);
assert(entry.currentState != _RouteLifecycle.push);
assert(entry.currentState != _RouteLifecycle.pushReplace);
assert(entry.currentState != _RouteLifecycle.replace);
if (entry.currentState == _RouteLifecycle.idle) {
continue;
}
case _RouteLifecycle.pushing: // Will exit this state when animation completes.
if (!seenTopActiveRoute && poppedRoute != null) {
entry.handleDidPopNext(poppedRoute);
}
seenTopActiveRoute = true;
case _RouteLifecycle.idle:
if (!seenTopActiveRoute && poppedRoute != null) {
entry.handleDidPopNext(poppedRoute);
}
seenTopActiveRoute = true;
// This route is idle, so we are allowed to remove subsequent (earlier)
// routes that are waiting to be removed silently:
canRemoveOrAdd = true;
case _RouteLifecycle.pop:
if (!entry.handlePop(
navigator: this,
previousPresent: _getRouteBefore(index, _RouteEntry.willBePresentPredicate)?.route)){
assert(entry.currentState == _RouteLifecycle.idle);
continue;
}
if (!seenTopActiveRoute) {
if (poppedRoute != null) {
entry.handleDidPopNext(poppedRoute);
}
poppedRoute = entry.route;
}
// 观察路由删除
_observedRouteDeletions.add(
_NavigatorPopObservation(entry.route, _getRouteBefore(index, _RouteEntry.willBePresentPredicate)?.route),
);
if (entry.currentState == _RouteLifecycle.dispose) {
// The pop finished synchronously. This can happen if transition
// duration is zero.
continue;
}
assert(entry.currentState == _RouteLifecycle.popping);
canRemoveOrAdd = true;
case _RouteLifecycle.popping:
// Will exit this state when animation completes.
break;
case _RouteLifecycle.complete:
entry.handleComplete();
assert(entry.currentState == _RouteLifecycle.remove);
continue;
case _RouteLifecycle.remove:
if (!seenTopActiveRoute) {
if (poppedRoute != null) {
entry.route.didPopNext(poppedRoute);
}
poppedRoute = null;
}
entry.handleRemoval(
navigator: this,
previousPresent: _getRouteBefore(index, _RouteEntry.willBePresentPredicate)?.route,
);
assert(entry.currentState == _RouteLifecycle.removing);
continue;
case _RouteLifecycle.removing:
if (!canRemoveOrAdd && next != null) {
// 我们还不允许移除这条路线
break;
}
entry.currentState = _RouteLifecycle.dispose;
continue;
case _RouteLifecycle.dispose:
// 延迟处理,直到didChangeNext/didChangePrevious被发送。
toBeDisposed.add(_history.removeAt(index));
entry = next;
case _RouteLifecycle.disposing:
case _RouteLifecycle.disposed:
case _RouteLifecycle.staging:
assert(false);
}
index -= 1;
next = entry;
entry = previous;
previous = index > 0 ? _history[index - 1] : null;
}
/// 通知所有的Navigator观察者路由的变化
_flushObserverNotifications();
/// 列表已经干净,发送didChangeNext/didChangePrevious通知
_flushRouteAnnouncement();
/// 宣布路由名字改变
if (widget.reportsRouteUpdateToEngine) {
final _RouteEntry? lastEntry = _lastRouteEntryWhereOrNull(_RouteEntry.isPresentPredicate);
final String? routeName = lastEntry?.route.settings.name;
if (routeName != null && routeName != _lastAnnouncedRouteName) {
SystemNavigator.routeInformationUpdated(uri: Uri.parse(routeName));
_lastAnnouncedRouteName = routeName;
}
}
/// 最后,移除所有标记项的覆盖项并进行处理
for (final _RouteEntry entry in toBeDisposed) {
_disposeRouteEntry(entry, graceful: true);
}
if (rearrangeOverlay) {
overlay?.rearrange(_allRouteOverlayEntries);
}
if (bucket != null) {
_serializableHistory.update(_history);
}
_flushingHistory = false;
}
void handlePush({ required NavigatorState navigator, required bool isNewFirst, required Route<dynamic>? previous, required Route<dynamic>? previousPresent }) {
// ...
final _RouteLifecycle previousState = currentState;
// 让新加入的route和Navigator引用绑定
route._navigator = navigator;
// install是将route转换为OverlayEntry,并插入到List<OverlayEntry>中的重要过程
route.install();
assert(route.overlayEntries.isNotEmpty);
// 完成新老界面的转换(didReplace/didPush),内部有一些事件和动画处理
if (currentState == _RouteLifecycle.push || currentState == _RouteLifecycle.pushReplace) {
final TickerFuture routeFuture = route.didPush();
currentState = _RouteLifecycle.pushing;
// tick结束后 刷新一遍
routeFuture.whenCompleteOrCancel(() {
if (currentState == _RouteLifecycle.pushing) {
currentState = _RouteLifecycle.idle;
assert(!navigator._debugLocked);
assert(() { navigator._debugLocked = true; return true; }());
navigator._flushHistoryUpdates();
assert(() { navigator._debugLocked = false; return true; }());
}
});
} else {
assert(currentState == _RouteLifecycle.replace);
route.didReplace(previous);
currentState = _RouteLifecycle.idle;
}
if (isNewFirst) {
route.didChangeNext(null);
}
// 将路由变化事件加到列表中
if (previousState == _RouteLifecycle.replace || previousState == _RouteLifecycle.pushReplace) {
navigator._observedRouteAdditions.add(
_NavigatorReplaceObservation(route, previousPresent),
);
} else {
assert(previousState == _RouteLifecycle.push);
navigator._observedRouteAdditions.add(
_NavigatorPushObservation(route, previousPresent),
);
}
}
ModalRoute的route.install
install是将route转换为OverlayEntry,并插入到List<OverlayEntry>
中的重要过程
dart
abstract class OverlayRoute<T> extends Route<T> {
/// Subclasses should override this getter to return the builders for the overlay.
@factory
Iterable<OverlayEntry> createOverlayEntries();
// ...
@override
List<OverlayEntry> get overlayEntries => _overlayEntries;
final List<OverlayEntry> _overlayEntries = <OverlayEntry>[];
// ...
@override
void install() {
assert(_overlayEntries.isEmpty);
_overlayEntries.addAll(createOverlayEntries());
super.install();
}
// ...
}
ModalRoute的createOverlayEntries
创建覆盖项(遮罩和展示)
dart
/// ModalRoute中的createOverlayEntries
/// ps: abstract class TransitionRoute<T> extends OverlayRoute<T>
abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T> {
// ...
@override
Iterable<OverlayEntry> createOverlayEntries() {
return <OverlayEntry>[
_modalBarrier = OverlayEntry(builder: _buildModalBarrier),
_modalScope = OverlayEntry(builder: _buildModalScope, maintainState: maintainState, canSizeOverlay: opaque),
];
}
// ...
}
ModalRoute的_buildModalScope
build展示的页面
dart
/// -> 关注_buildModalScope,创建可视区域
abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T> {
// one of the builders
Widget _buildModalScope(BuildContext context) {
// To be sorted before the _modalBarrier.
return _modalScopeCache ??= Semantics(
sortKey: const OrdinalSortKey(0.0),
child: _ModalScope<T>(
key: _scopeKey,
route: this,
// _ModalScope calls buildTransitions() and buildChild(), defined above
),
);
}
}
/// --- _ModalScope -> _ModalScopeState
class _ModalScope<T> extends StatefulWidget {
const _ModalScope({
super.key,
required this.route,
});
final ModalRoute<T> route;
@override
_ModalScopeState<T> createState() => _ModalScopeState<T>();
}
class _ModalScopeState<T> extends State<_ModalScope<T>> {
// ...
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: widget.route.restorationScopeId,
builder: (BuildContext context, Widget? child) {
assert(child != null);
return RestorationScope(
restorationId: widget.route.restorationScopeId.value,
child: child!,
);
},
// ... 省略很多嵌套parent
child: _page ??= RepaintBoundary(
key: widget.route._subtreeKey, // immutable
child: Builder(
builder: (BuildContext context) {
return widget.route.buildPage( // 调用buildPage
context,
widget.route.animation!,
widget.route.secondaryAnimation!,
);
},
),
),
);
}
}
/// 调用buildPage
/// GetPageRouteTransitionMixin on PageRoute 拓展了buildPage方法,增加了buildContent方法(会用在buildPage里)
mixin GetPageRouteTransitionMixin<T> on PageRoute<T> {
/// Builds the primary contents of the route.
@protected
Widget buildContent(BuildContext context);
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
final child = buildContent(context); //调用buildContent获得当前的widgetUI
final Widget result = Semantics(
scopesRoute: true,
explicitChildNodes: true,
child: child,
);
return result;
}
}
/// GetPageRoute的 buildContent 是通过混入 GetPageRouteTransitionMixin 得到的
/// 所以可以获得了mixin中的buildContent方法并重写
class GetPageRoute<T> extends PageRoute<T>
with GetPageRouteTransitionMixin<T>, PageRouteReportMixin {
Widget _getChild() {
// 检查缓存:首先检查 _child 是否已经被构建并缓存。如果 _child 已存在,则直接返回它,避免重复构建。
if (_child != null) return _child!;
// 中间件处理器:创建一个 MiddlewareRunner 实例,并传入中间件(middlewares)。
// MiddlewareRunner 将用于在页面构建的不同阶段运行中间件相关的逻辑。
final middlewareRunner = MiddlewareRunner(middlewares);
// 收集依赖绑定:合并 bindings 和 binding,形成一个新的集合 localbindings。
// 这些绑定(bindings)表示页面所需的依赖关系,它们将在构建页面之前进行处理和注入。
final localbindings = [
if (bindings != null) ...bindings!,
if (binding != null) ...[binding!]
];
// 运行绑定中间件:通过 middlewareRunner 运行中间件,并处理 onBindingsStart 回调。这可能会修改或过滤绑定列表。
final bindingsToBind = middlewareRunner.runOnBindingsStart(localbindings);
// 依赖注入:对需要绑定的依赖(bindingsToBind)进行依赖注入,即调用每个绑定的 dependencies 方法,以便提前注入页面所需的依赖。
if (bindingsToBind != null) {
for (final binding in bindingsToBind) {
binding.dependencies();
}
}
// 运行页面构建开始中间件:调用 middlewareRunner 的 runOnPageBuildStart 方法,处理 onPageBuildStart 回调。
// 这用于在页面构建开始时运行相关的中间件逻辑。此时,页面还未被真正构建。
final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!;
_child = middlewareRunner.runOnPageBuilt(pageToBuild());
// 返回构建好的 Widget:最终返回构建好的 Widget,并缓存到 _child 中以供后续使用。
return _child!;
}
@override
Widget buildContent(BuildContext context) {
return _getChild();
}
}
这下被你知道你的传入的 Route 是如何被使用的了
插入到Overlay中
dart
class OverlayState extends State<Overlay> with TickerProviderStateMixin {
void insertAll(Iterable<OverlayEntry> entries, { OverlayEntry? below, OverlayEntry? above }) {
// ...
for (final OverlayEntry entry in entries) {
assert(entry._overlay == null);
// 将每一个要插入到集合中的OverlayEntry绑定自身
// 插入是由Overlay中进行的,但删除却是每个元素自己调用的
entry._overlay = this;
}
setState(() {
// 集合插入完成后,将触发Overlay的 rebuild
_entries.insertAll(_insertionIndex(below, above), entries);
});
}
@override
Widget build(BuildContext context) {
// 创建列表:首先创建一个空的 _OverlayEntryWidget 列表 children,用于存储每个 OverlayEntry 的 Widget。
final List<_OverlayEntryWidget> children = <_OverlayEntryWidget>[];
// onstage:用于跟踪当前是否在构建 "onstage"(可见的)内容。初始化为 true。
bool onstage = true;
// onstageCount:用于计数可见内容的数量。初始化为 0。
int onstageCount = 0;
// 遍历 _entries:反向遍历 _entries 列表,该列表包含了所有的 OverlayEntry。
for (final OverlayEntry entry in _entries.reversed) {
// 处理 "onstage" 条目:
// 添加到列表:将新的 _OverlayEntryWidget 添加到 children 列表中。
if (onstage) {
// 增加计数:如果当前条目是 "onstage",增加 onstageCount。
onstageCount += 1;
children.add(_OverlayEntryWidget(
key: entry._key,
overlayState: this,
entry: entry,
));
// 检查不透明性:如果条目是不透明 (opaque),设置 onstage = false,不再继续添加 "onstage" 条目。
if (entry.opaque) {
onstage = false;
}
} else if (entry.maintainState) {
// 处理非 "onstage" 条目:
// 如果当前条目不是 "onstage" 且设置为保持状态 (maintainState),则继续将该条目添加到 children,
// 但 tickerEnabled 为 false,表示它的动画或其它时间相关的属性被禁用。
// 不是maintainState的不加入
children.add(_OverlayEntryWidget(
key: entry._key,
overlayState: this,
entry: entry,
tickerEnabled: false,
));
}
}
return _Theater(
// 跳过不需要渲染的widget【注释4 5 6】
skipCount: children.length - onstageCount,
clipBehavior: widget.clipBehavior,
children: children.reversed.toList(growable: false),
);
}
}
pop代码速看
待写~
其他
RouteAware
dart
/// 一个接口,用于使对象感知其当前的 [Route]
///
/// 和 [RouteObserver] 一起使用,使当前路由能够感知 [Navigator] 会话历史的变化
abstract mixin class RouteAware {
/// 当前路由进栈时调用
void didPush() { }
/// 当一个新路由进栈,当前路由不再显示时调用
void didPushNext() { }
/// 当前路由出栈时调用
void didPop() { }
/// 顶部路由出栈时,当前路由显示时调用
void didPopNext() { }
}