页面路由的实现与差异

在前面的页面分析过程中,多次提到了channel通道的使用。这块通道逻辑都在container_coordinator.dart中,coordinator有调度员的意思,这大概就是路由管理封装类命名的原因吧。

路由绑定

既然是容器调度,那么调度员第一步要做的是什么呢? 自然是先要有可以被灵活调度的容器。因此,Boost使用的第一步就是先进行路由的注册配置。当我们执行registerPageBuilders时,它的具体实现如下:

/// flutter_boost.dart
///Register a map builders
void registerPageBuilders(Map<String, PageBuilder> builders) {
  ContainerCoordinator.singleton.registerPageBuilders(builders);
}

可以看到与原生route非常类似,我们仅仅是传入了一个键值对的Map。其中Key是页面路由的么名字,Value其实是一个Builder,类似于WidgetBuilder。差异在于Boost额外封装了一些容器维度的属性,比如说页面的唯一标识,参数等。所以PageBuilder可以简单理解为就是一个个性化的专用WidgetBuilder。

页面配置

有了路由表以后,比那可以在合适的时候调用,从路由表中获取目标页面的PageBuilder,然后构建出一个真正的Widget页面。这一步又是怎么实现的呢?

在《顶层容器栈的实现》一节中,我们通过检索路由表被调用的逻辑,知道当Dart侧收到页面创建事件willShowPageContainer时,回去实例化一个页面。实例化页面的时候,根据事件的参数,构造了一个页面维度的配置,叫做BoostContainerSettings,配置中的WidgetBuilder是用和原生路由配合工作的。

class BoostContainerSettings {
  final String uniqueId;
  final String name;
  final Map params;
  final WidgetBuilder builder;

  const BoostContainerSettings(
      {this.uniqueId = 'default',
      this.name = 'default',
      this.params,
      this.builder});
}

配置的生成逻辑如下,当WidgetBuilder被Flutter触发的时候,将构建Widget的任务委托给了PageBuilder处理:

/// conatiner_coordinator.dart
BoostContainerSettings _createContainerSettings(
  String name, Map params, String pageId) {
  Widget page;

  final BoostContainerSettings routeSettings = BoostContainerSettings(
    uniqueId: pageId,
    name: name,
    params: params,
    builder: (BuildContext ctx) {
      //Try to build a page using keyed builder.
      if (_pageBuilders[name] != null) {
        page = _pageBuilders[name](name, params, pageId);
      }

      //Build a page using default builder.
      if (page == null && _defaultPageBuilder != null) {
        page = _defaultPageBuilder(name, params, pageId);
      }

      assert(page != null);
      Logger.log('build widget:$page for page:$name($pageId)');

      return page;
    });

  return routeSettings;
}

进一步的,我们继续分析下,这个WidgetBuilder什么时候会被Flutter触发呢?

简单来说是在Navigator中触发的。我们已经知道BoostContainer本身继承了Navigator,所以它是被当做Navigator来使用的。在构建BoostContainer时,构造器如下:

factory BoostContainer.obtain(
        Navigator navigator, BoostContainerSettings settings) =>
    BoostContainer(
        key: GlobalKey<BoostContainerState>(),
        settings: settings,
        onGenerateRoute: (RouteSettings routeSettings) {
          if (routeSettings.name == '/') {
            return BoostPageRoute<dynamic>(
                pageName: settings.name,
                params: settings.params,
                uniqueId: settings.uniqueId,
                animated: false,
                settings: routeSettings,
                builder: settings.builder);
          } else {
            return navigator.onGenerateRoute(routeSettings);
          }
        },
        observers: <NavigatorObserver>[
          ContainerNavigatorObserver.bindContainerManager()
        ],
        onUnknownRoute: navigator.onUnknownRoute);

通过onGenerateRoute,将Boost的个性化页面创建最终与Navigator关联了起来。

Boost事件定义

事件的定义目前内置了4种,分别是:

  • backPressedCallback 返回键事件
  • foreground 页面进入前台
  • background 页面进入后台
  • scheduleFrame 调度一次页面绘制

前后台事件触发后,会对当前状态进行标记,具体是通过Boost单例,获取的当前的目标Container容器;最后通知观察者。 返回事件的处理则会分发至当前Container,触发一次页面的pop动作。

Boost方法定义

在使用Boost过程中,我们可以观测到很多标签日志输出,如果要查方法相关的日志,可以过滤关键词onMetohdCall。 目前支持的核心方法包括:

  • didInitPageContainer
  • willShowPageContainer
  • didShowPageContainer
  • willDisappearPageContainer
  • didDisappearPageContainer
  • willDeallocPageContainer
  • onNativePageResult

几乎都是围绕着两个页面切换过程中的状态进行的定义。有一个需要注意就是针对页面show的两个事件处理:

  • willShowPageContainer
  • didShowPageContainer

willShow在源码中不会通知其自定义的生命周期回调,didShow会通知。除此之外,两者的实现中都有对页码创建。为什么会存在这种逻辑,目前单纯分析Dart侧代码得不到解释,后续在分析Native源码时可以进一步确认相关调用链路。

powered by Gitbook最近更新 2020-03-24

results matching ""

    No results matching ""