公告

微信

欢迎大家私信交流

Skip to content

Flutter路由源码

参考来源:

  1. https://juejin.cn/post/6844903798398255111

从Navigator的push方法去探索源码,并结合GetX跳转进行分析。

push代码速看

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() { }
}

上次更新于: