入口方法

  1. void runApp(Widget app) {
  2. WidgetsFlutterBinding.ensureInitialized()
  3. ..scheduleAttachRootWidget(app)
  4. ..scheduleWarmUpFrame();
  5. }
  1. @protected
  2. void scheduleAttachRootWidget(Widget rootWidget) {
  3. Timer.run(() {
  4. attachRootWidget(rootWidget);
  5. });
  6. }
  1. void attachRootWidget(Widget rootWidget) {
  2. final bool isBootstrapFrame = renderViewElement == null;
  3. _readyToProduceFrames = true;
  4. _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
  5. container: renderView,
  6. debugShortDescription: '[root]',
  7. child: rootWidget,
  8. ).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);
  9. if (isBootstrapFrame) {
  10. SchedulerBinding.instance.ensureVisualUpdate();
  11. }
  12. }

顶层组件和顶层元素的初始化场景。

  1. RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T>? element ]) {
  2. if (element == null) {
  3. owner.lockState(() {
  4. element = createElement();
  5. assert(element != null);
  6. element!.assignOwner(owner);
  7. });
  8. owner.buildScope(element!, () {
  9. element!.mount(null, null);
  10. });
  11. } else {
  12. element._newWidget = this;
  13. element.markNeedsBuild();
  14. }
  15. return element!;
  16. }

此方法主要返回 RenderObjectToWidgetElement。如果 没有根元素,则执行 BuildOwner 的两个方法:
1. lockState 方法传入回调,创建 Element tree 的根节点
2. buildScope 方法传入根元素和回调,根元素挂载,完成 Element tree 、 RenderObject tree 的构建工作

渲染对象

对于树形结构来说,节点分为三种类型: 单子 、多子 和 叶子 。顾名思义,单子只允许有一个子节点;多子可以有多个子节点;叶子不能拥有子节点。每个节点都具有 layout 方法,那么只要触发根节点的 layout ,子级可以在自己的 layout 中触发下一级的 layout 。

Element 整体上演化出两大类:
1. ComponentElement (组合型)
1.1 StatelessElement
1.2 StatefulElement
1.3 ProxyElement
2. RenderObjectElement(渲染型)
2.1 SingleChildRenderObjectElement // 单子节点
2.2 MutiChildRenderObjectElement // 多子节点
2.3 LeafRenderObjectElement // 叶子节点

单子渲染对象

渲染对象混入 RenderObjectWithChildMixin ,才能具有持有子级的能力。

多子渲染对象

混入了ContainerRenderObjectMixin 来实现 多个子级。

StatefulWidget 和 State 、StateElement 之间的关系

Flutter渲染机制 - 图1

State 的回调触发时机

  1. State.initState() StatefulElement # mount 方法时,被触发;接着 触发State.didChangeDependencies();StatefulElement # build 方法,触发 State.build();StatefulElement # update 方法,会触发 State.didUpdateWidget();StatefulElement # unmount ,触发State.dispose()。<br />State 的 回调与 Element 的回调 深度绑定。State 也可以监听到 Element 在 Element tree 上的一些行为: mount、active、inactive、unmount。

Element 节点的更新

setState 的本质是元素节点的更新。变化的是 Widget,而 Element tree 、 RenderObject tree 中的节点仍然是之前的对象,只不过 RenderObject 的属性进行重新设置而已,等属性相等时返回,保证了 RenderObject 属性更新时不会有不必要的操作。

Key

解决的本质问题是,在组件位置变化时,Element 无法感知的问题。

  1. Map<Key,Element>? oldKeyedChildren;

LocalKey
UniqueKey
ValueKey
ObjectKey
GlobalKey
LocalKey 保证的是 相同父级 Widget 的身份唯一性。GlobalKey 是 整个应用中,Widget 的身份的唯一。

  1. final Map<GlobalKey,Element> _globalKeyRegistry = <GlobalKey,Element>{};

ScheduleBinding

  1. void addPersistentCallBack(FrameCallBack callback) // 每一帧都会调用(持久帧)
  2. void addPostFrameCallBack(FrameCallBack callback) // 仅在帧尾调用
  3. WidgetsBinding.instance!.addPostCallBack((){
  4. // demo
  5. });

这里的 WidgetsBinding 的实例 实际上是 WidgetsFlutterBinding 类型的单一实例。

BuildOwner

主要维护 _dirtyElements 元素列表, 用于收集 被标脏的元素,这些元素将在 BuildOwner 的 buildScope 中 更新。BuildOwner 负责管理 Element 对象,例如 脏元素列表、非激活元素表、GlobalKey 与 元素映射。

PipelineOwner

  1. List<RenderObject> _nodesNeedingLayout = <RenderObject>[];

通过 _nodesNeedingLayout 列表收集需要执行布局的渲染对象。

  1. List<RenderObject> _nodesNeedingPaint = <RenderObject>[];
  2. final List<RenderObject> _nodesNeedingCompositingBitsUpdate = <RenderObject>[];

RenderObject 的 markNeedsLayout 、markNeedsPaint 和 markNeedsCompositingBitsUpdate 的方法,把 RenderObject 加入 需要 布局、合成、绘制的列表。
并在 脏元素 构建完后,进行 布局、合成、绘制。

RenderObject

  1. bool get isRepaintBoundary => false;
  2. boll _needsPaint => true;

Flutter渲染机制 - 图2

Layer

Layer 节点 是在 RenderObject 绘制期间被添加到 tree 上,并非所有 RenderObject 都会被 添加到 层上,添加到层的目的是为了对某一区域做特殊处理。
打印当前界面的 Layer 。

  1. debugDumpLayerTree();

Layer :

  1. ContainerLayer
  2. TextureLayer
  3. PictureLayer
  4. PlatfromLayer
  5. PlatfromViewLayer
  6. PerformanceOverlayLayer

    Scene

    Scene 的构建是在根 RenderObject 的 compositeFrame 中进行的,使用 根 RenderObject 持有的 layer ,触发 buildScene 方法,将图层添加场景中,之所以显示界面,是因为 _window 对象对 scene 的渲染。