【Flutter】 从runApp到三棵树

        已经学习和使用Flutter月余,总想总结一下关于Flutter的三棵树构建过程,今天趁着摸鱼时间,总结一下。总结从runApp开始,通过代码我们可知,整个启动过程分为了三个步骤

  1. WidgetsFlutterBinding 初始化
  2. 绑定根节点创建核心三棵树
  3. 绘制热身帧
void runApp(Widget app) {
  WidgetsFlutterBinding.ensureInitialized() //WidgetsFlutterBinding 初始化
    ..scheduleAttachRootWidget(app) //绑定根节点创建核心三棵树
    ..scheduleWarmUpFrame(); //绘制热身帧
}

        下面再从这几个方法入手分别进行研究,首先是ensureInitialized

/// A concrete binding for applications based on the Widgets framework.
///
/// This is the glue that binds the framework to the Flutter engine.
///
/// When using the widgets framework, this binding, or one that
/// implements the same interfaces, must be used. The following
/// mixins are used to implement this binding:
///
/// * [GestureBinding], which implements the basics of hit testing.
/// * [SchedulerBinding], which introduces the concepts of frames.
/// * [ServicesBinding], which provides access to the plugin subsystem.
/// * [PaintingBinding], which enables decoding images.
/// * [SemanticsBinding], which supports accessibility.
/// * [RendererBinding], which handles the render tree.
/// * [WidgetsBinding], which handles the widget tree.
class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
  /// Returns an instance of the binding that implements
  /// [WidgetsBinding]. If no binding has yet been initialized, the
  /// [WidgetsFlutterBinding] class is used to create and initialize
  /// one.
  ///
  /// You only need to call this method if you need the binding to be
  /// initialized before calling [runApp].
  ///
  /// In the `flutter_test` framework, [testWidgets] initializes the
  /// binding instance to a [TestWidgetsFlutterBinding], not a
  /// [WidgetsFlutterBinding]. See
  /// [TestWidgetsFlutterBinding.ensureInitialized].
  static WidgetsBinding ensureInitialized() {
    if (WidgetsBinding._instance == null) {
      WidgetsFlutterBinding();
    }
    return WidgetsBinding.instance;
  }
}

         flutter 的注释写的非常的好,我们结合代码可以得到这样的一个结论 ensureInitialized 方法最终返回的是WidgetsBinding的instance实例对象。这个对象的创建过程,其实就是所有binding调用自己的initInstances来实现的,我们从最外层的binding开始探索。

/// The glue between the widgets layer and the Flutter engine.
mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding {
  @override
  void initInstances() {
    super.initInstances();
    _instance = this;

    assert(() {
      _debugAddStackFilters();
      return true;
    }());


    //创建一个管理Widgets的类对象
    //BuildOwner类用来跟踪哪些Widget需要重建,
    //并处理用于Widget树的其他任务,例如管理不活跃的Widget等,调试模式触发重建等。
    _buildOwner = BuildOwner();

    //2、回调方法赋值,当第一个可构建元素被标记为脏时调用。
    buildOwner!.onBuildScheduled = _handleBuildScheduled;
    
    //3、platformDispatcher 负责派发从平台配置到屏幕和窗口的创建或销毁的事件,里面定义了许多的native方法,负责flutter与平台底层的交互。
    //这里定义了一些和这些底层(Flutter 引擎 )的回调
    platformDispatcher.onLocaleChanged = handleLocaleChanged;
    platformDispatcher.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
    SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
    assert(() {
      FlutterErrorDetails.propertiesTransformers.add(debugTransformDebugCreator);
      return true;
    }());
    platformMenuDelegate = DefaultPlatformMenuDelegate();
  }
//....
}

        从上面的代码我们可以知道,WidgetBinding 是 Widget 层和 Flutter 引擎之间的粘合剂。在它的创建过程里,我们创建了一个BuildOwner对象,并设置了一些与引擎相关的回调构建回调。接下来我们再看一下RendererBinding 中做了什么

/// The glue between the render tree and the Flutter engine.
mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable {
  @override
  void initInstances() {
    super.initInstances();
    //1.创建管理rendering渲染管道的类 提供接口调用用来触发渲染。
    _instance = this;
    _pipelineOwner = PipelineOwner(
      onNeedVisualUpdate: ensureVisualUpdate,
      onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
      onSemanticsUpdate: _handleSemanticsUpdate,
      onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
    );
    //2.一堆platformDispatcher变化相关的回调监听
    platformDispatcher
      ..onMetricsChanged = handleMetricsChanged
      ..onTextScaleFactorChanged = handleTextScaleFactorChanged
      ..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
      ..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
      ..onSemanticsAction = _handleSemanticsAction;
    //3.创建RenderView对象,也就是RenderObject渲染树的根节点
    initRenderView();
    _handleSemanticsEnabledChanged();
    assert(renderView != null);
    addPersistentFrameCallback(_handlePersistentFrameCallback);
    initMouseTracker();
    if (kIsWeb) {
      addPostFrameCallback(_handleWebFirstFrame);
    }
  }

  /// ...
 

  /// Creates a [RenderView] object to be the root of the
  /// [RenderObject] rendering tree, and initializes it so that it
  /// will be rendered when the next frame is requested.
  ///
  /// Called automatically when the binding is created.
  void initRenderView() {
    assert(!_debugIsRenderViewInitialized);
    assert(() {
      _debugIsRenderViewInitialized = true;
      return true;
    }());
    renderView = RenderView(configuration: createViewConfiguration(), window: window);
    renderView.prepareInitialFrame();
  }

      从上面的代码我们可以知道,RendererBinding 是  Renderer层和 Flutter 引擎之间的粘合剂。在它的创建过程里,我们创建了一个渲染管道的对象PipelineOwner,并设置了一些与引擎相关的回调构建回调。最重要的是,在这里他创建了一个RenderObject树根RenderView。

        其余的绑定,暂时没有看《TODO》,如果再有时间的话,可以继续探索,而我今天主要想追寻三棵树的创建,所以到这里就可以了。我们可以得到这样的一个结论

在bindding初始化的过程中,我们已经创建了3个非常有用的对象。

BuildOwner         widget管理对象

PipelineOwner    渲染管道管理对象

RenderView        渲染树的树根


        Binding对象创建好之后调用,scheduleAttachRootWidget,源码可知,通过Timer异步调用attachRootWidget。

/// Schedules a [Timer] for attaching the root widget.
  ///
  /// This is called by [runApp] to configure the widget tree. Consider using
  /// [attachRootWidget] if you want to build the widget tree synchronously.
  @protected
  void scheduleAttachRootWidget(Widget rootWidget) {
    Timer.run(() {
      attachRootWidget(rootWidget);
    });
  }

  /// Takes a widget and attaches it to the [renderViewElement], creating it if
  /// necessary.
  ///
  /// This is called by [runApp] to configure the widget tree.
  ///
  /// See also:
  ///
  ///  * [RenderObjectToWidgetAdapter.attachToRenderTree], which inflates a
  ///    widget and attaches it to the render tree.
  void attachRootWidget(Widget rootWidget) {
    //1、是不是启动帧,即看renderViewElement是否有赋值,赋值时机为步骤2
    final bool isBootstrapFrame = renderViewElement == null;
    _readyToProduceFrames = true;
    //2、RenderObjectToWidgetAdapter 桥梁创建RenderObject、Element、Widget关系树,
    //_renderViewElement值为attachToRenderTree方法返回值
    _renderViewElement = RenderObjectToWidgetAdapter(
      container: renderView//渲染树的树根,
      debugShortDescription: '[root]',
      child: rootWidget,
    //3、attach过程,renderViewElement 值就是_renderViewElement自己
    //此时由于调用完appach才赋值,所以首次进来也是null
    ).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement?);
    if (isBootstrapFrame) {
      SchedulerBinding.instance.ensureVisualUpdate();
    }
  }

RenderObjectToWidgetAdapter对象 是widget树的树根,他第一个孩子就是runApp传进来的rootWidget

class RenderObjectToWidgetAdapter extends RenderObjectWidget {
  /// Creates a bridge from a [RenderObject] to an [Element] tree.
  ///
  /// Used by [WidgetsBinding] to attach the root widget to the [RenderView].
  RenderObjectToWidgetAdapter({
    this.child,
    required this.container,
    this.debugShortDescription,
  }) : super(key: GlobalObjectKey(container));

  /// The widget below this widget in the tree.
  ///我们编写dart的runApp函数参数中传递的Flutter应用Widget树根
  /// {@macro flutter.widgets.ProxyWidget.child}
  final Widget? child;

  /// The [RenderObject] that is the parent of the [Element] created by this widget.
  /// 继承自RenderObject,来自PipelineOwner对象的rootNode属性,一个Flutter全局只有一个PipelineOwner实例。
  final RenderObjectWithChildMixin container;

  /// A short description of this widget used by debugging aids.
  final String? debugShortDescription;

  @override
  RenderObjectToWidgetElement createElement() => RenderObjectToWidgetElement(this);

  @override
  RenderObjectWithChildMixin createRenderObject(BuildContext context) => container;

  @override
  void updateRenderObject(BuildContext context, RenderObject renderObject) { }

  /// Inflate this widget and actually set the resulting [RenderObject] as the
  /// child of [container].
  ///
  /// If `element` is null, this function will create a new element. Otherwise,
  /// the given element will have an update scheduled to switch to this widget.
  ///
  /// Used by [runApp] to bootstrap applications.
  RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement? element ]) {
        
    /// 当前第一次调用所以为null
    if (element == null) {
      //在lockState里面代码执行过程中禁止调用setState方法
      owner.lockState(() {
        //创建element对象
        element = createElement();
        assert(element != null);
        element!.assignOwner(owner);
      });
      owner.buildScope(element!, () {
        //挂到Element树上
        element!.mount(null, null);
      });
    } else {
      //更新widget树时_newWidget赋值为新的,然后element树根标记为markNeedsBuild
      element._newWidget = this;
  /// Marks the element as dirty and adds it to the global list of widgets to
  /// rebuild in the next frame.
      element.markNeedsBuild();
    }
    return element!;
  }

  @override
  String toStringShort() => debugShortDescription ?? super.toStringShort();
}

dapter 

来来来,Flutter Widget 体系架构与 UI 渲染流程 - 掘金

你可能感兴趣的:(flutter,android,android,studio)