入口方法
void runApp(Widget app) {WidgetsFlutterBinding.ensureInitialized()..scheduleAttachRootWidget(app)..scheduleWarmUpFrame();}
@protectedvoid scheduleAttachRootWidget(Widget rootWidget) {Timer.run(() {attachRootWidget(rootWidget);});}
void attachRootWidget(Widget rootWidget) {final bool isBootstrapFrame = renderViewElement == null;_readyToProduceFrames = true;_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(container: renderView,debugShortDescription: '[root]',child: rootWidget,).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);if (isBootstrapFrame) {SchedulerBinding.instance.ensureVisualUpdate();}}
顶层组件和顶层元素的初始化场景。
RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T>? element ]) {if (element == null) {owner.lockState(() {element = createElement();assert(element != null);element!.assignOwner(owner);});owner.buildScope(element!, () {element!.mount(null, null);});} else {element._newWidget = this;element.markNeedsBuild();}return element!;}
此方法主要返回 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 之间的关系
State 的回调触发时机
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 无法感知的问题。
Map<Key,Element>? oldKeyedChildren;
LocalKey
UniqueKey
ValueKey
ObjectKey
GlobalKey
LocalKey 保证的是 相同父级 Widget 的身份唯一性。GlobalKey 是 整个应用中,Widget 的身份的唯一。
final Map<GlobalKey,Element> _globalKeyRegistry = <GlobalKey,Element>{};
ScheduleBinding
void addPersistentCallBack(FrameCallBack callback) // 每一帧都会调用(持久帧)void addPostFrameCallBack(FrameCallBack callback) // 仅在帧尾调用WidgetsBinding.instance!.addPostCallBack((){// demo});
这里的 WidgetsBinding 的实例 实际上是 WidgetsFlutterBinding 类型的单一实例。
BuildOwner
主要维护 _dirtyElements 元素列表, 用于收集 被标脏的元素,这些元素将在 BuildOwner 的 buildScope 中 更新。BuildOwner 负责管理 Element 对象,例如 脏元素列表、非激活元素表、GlobalKey 与 元素映射。
PipelineOwner
List<RenderObject> _nodesNeedingLayout = <RenderObject>[];
通过 _nodesNeedingLayout 列表收集需要执行布局的渲染对象。
List<RenderObject> _nodesNeedingPaint = <RenderObject>[];final List<RenderObject> _nodesNeedingCompositingBitsUpdate = <RenderObject>[];
RenderObject 的 markNeedsLayout 、markNeedsPaint 和 markNeedsCompositingBitsUpdate 的方法,把 RenderObject 加入 需要 布局、合成、绘制的列表。
并在 脏元素 构建完后,进行 布局、合成、绘制。
RenderObject
bool get isRepaintBoundary => false;boll _needsPaint => true;
Layer
Layer 节点 是在 RenderObject 绘制期间被添加到 tree 上,并非所有 RenderObject 都会被 添加到 层上,添加到层的目的是为了对某一区域做特殊处理。
打印当前界面的 Layer 。
debugDumpLayerTree();
Layer :
