flutter_boost如何接管Navigator

2019-11-12  本文已影响0人  夏广成

以下分析基于 flutter_boost 分支 feature/flutter_1.9_androidx_upgrade

flutter_boost为了实现每个widget页面都有一个native端的activity页面与之对应,那么打开新的flutter页面时,就指定了特殊的打开页面方式:

FlutterBoost.singleton.open();

这个函数的作用就是通知native端,开始创建activity。当native端来到了

setContentView(createFlutterView());

时,就会重新进入到flutter侧的ContainerCoordinator类中的"didInitPageContainer",其实此时并没有实质上的改变,就是创建了一个与ContainerLifeCycle.Init对应的ContainerSettings。当native侧的代码进入到onResume()后,又会发送事件进入到flutter侧的"didShowPageContainer"。此时开始了真正意义上的flutter页面创建。

  bool nativeContainerDidShow(String name, Map params, String pageId) {
    FlutterBoost.containerManager
        ?.showContainer(_createContainerSettings(name, params, pageId));
    performContainerLifeCycle(_createContainerSettings(name, params, pageId),
        ContainerLifeCycle.Appear);
    return true;
  }

因此需要重点关注ContainerManager中的showContainer()。在这个方法中会先判断_onStage是不是就是要显示的页面,如果不是就从_offStage中查找。其中_onStage定义为当前正在显示的页面。_offStage是存放不是正在显示的页面的集合。如果在_offStage中查找不到,就会进入pushContainer()

  void pushContainer(BoostContainerSettings settings) {
    ……

    _offstage.add(_onstage);
    _onstage = BoostContainer.obtain(widget.initNavigator, settings);

    setState(() {});

   ……
  }

这里新创建了一个BoostContainer。并且赋值给了_onStage,然后通过setStage()刷新widgetTree。由于重写了setStage(),因此当调用进入setStage()之后,又进入了_refreshOverlayEntries()。在该函数中

void _refreshOverlayEntries() {
    final OverlayState overlayState = _overlayKey.currentState;

    if (overlayState == null) {
      return;
    }

    if (_leastEntries != null && _leastEntries.isNotEmpty) {
      for (_ContainerOverlayEntry entry in _leastEntries) {
        entry.remove();
      }
    }

    final List<BoostContainer> containers = <BoostContainer>[];
    containers.addAll(_offstage);

    assert(_onstage != null, 'Should have a least one BoostContainer');
    containers.add(_onstage);

    _leastEntries = containers
        .map<_ContainerOverlayEntry>(
            (BoostContainer container) => _ContainerOverlayEntry(container))
        .toList(growable: false);
    ///真正的页面显示是在这里
    overlayState.insertAll(_leastEntries);
  ……
   
  }

最后一行,真正意义上实现了页面显示。

overlayState.insertAll(_leastEntries);

overlayState是系统Navigator管理的overlay的状态。但是我们自始至终都没有使用Navigator啊,这个overlayState是如何生效的呢?根据之前的分析我们了解到ContainerManager作为整个flutterModule的根root,然后提供给了MaterialApp。在ContainerManagerState的build方法中,就是直接生成了一个overlay,返回给了整个flutter使用

  @override
  Widget build(BuildContext context) {
    return Overlay(
      key: _overlayKey,
      initialEntries: const <OverlayEntry>[],
    );
  }

此时我们在_refreshOverlayEntries()中获取的overlayState正是这个overlay的state。下面是整个流程的伪代码

class MaterialApp{
  //在main.dart中初始化FlutterBoost时返回的
  builder:BoostContainerManager(initNavigator)
}

class BoostContainerManager{
  builder:Overlay()
}

class _ContainerOverlayEntry extends OverlayEntry{
  builder:BoostContainer.copyWith(initNavigator)
}

class BoostContainer extends Navigator{
  BoostContainerSettings settings;
}

class BoostContainerSettings{
  final WidgetBuilder builder;
  //也就是我们在main.dart中注册路由时使用的。
  builder:FlutterBoost.singleton.registerPageBuilders();
}

上一篇 下一篇

猜你喜欢

热点阅读