本文是『 深刻浅出 Flutter Framework 』系列文章的第二篇,对 BuildOwer 相关内容进行简要地分析介绍,为下一篇文章介绍 Element 做准备 (因为篇幅缘由将其单独提出来)。git
本文同时发表于个人我的博客github
本系列文章将深刻 Flutter Framework 内部逐步去分析其核心概念和流程,主要包括:markdown
BuildOwer
在 Element 状态管理上起到重要做用:oop
这是咱们遇到的第一个 Owner,后面还有
PipeOwner
。post
整棵「Element Tree」共享同一个BuildOwer
实例 (全局的),在 Element 挂载过程当中由 parent 传递给 child element。ui
@mustCallSuper
void mount(Element parent, dynamic newSlot) {
_parent = parent;
_slot = newSlot;
_depth = _parent != null ? _parent.depth + 1 : 1;
_active = true;
if (parent != null) // Only assign ownership if the parent is non-null
_owner = parent.owner;
}
复制代码
以上是Element
基类的mount
方法,第 8 行将 parent.owner 赋给了 child。this
BuildOwer
实例由WidgetsBinding
负责建立,并赋值给「Element Tree」的根节点RenderObjectToWidgetElement
,此后随着「Element Tree」的建立逐级传递给子节点。(具体流程后续文章会详细分析)spa
通常状况下并不须要咱们手动实例化BuildOwer
,除非须要离屏沉浸 (此时须要构建 off-screen element tree)设计
BuildOwer
两个关键成员变量:code
final _InactiveElements _inactiveElements = _InactiveElements();
final List<Element> _dirtyElements = <Element>[];
复制代码
其命名已清晰表达了他们的用途:分别用于存储收集到的「Inactive Elements」、「Dirty Elements」。
那么BuildOwer
是如何收集「Dirty Elements」的呢? 对于须要更新的 element,首先会调用Element.markNeedsBuild
方法,如前文讲到的State.setState
方法:
void setState(VoidCallback fn) {
final dynamic result = fn() as dynamic;
_element.markNeedsBuild();
}
复制代码
以下,Element.markNeedsBuild
调用了BuildOwer.scheduleBuildFor
方法:
void markNeedsBuild() {
if (!_active)
return;
if (dirty)
return;
_dirty = true;
owner.scheduleBuildFor(this);
}
复制代码
BuildOwer.scheduleBuildFor
方法作了 2 件事:
onBuildScheduled
,该方法(实际上是个callback)会通知 Engine 在下一帧须要作更新操做;_dirtyElements
中。void scheduleBuildFor(Element element) {
assert(element.owner == this);
onBuildScheduled();
_dirtyElements.add(element);
element._inDirtyList = true;
}
复制代码
此后,在新一帧绘制到来时,WidgetsBinding.drawFrame
会调用BuildOwer.buildScope
方法:
void buildScope(Element context, [ VoidCallback callback ]) {
if (callback == null && _dirtyElements.isEmpty)
return;
try {
if (callback != null) {
callback();
}
_dirtyElements.sort(Element._sort);
int dirtyCount = _dirtyElements.length;
int index = 0;
while (index < dirtyCount) {
_dirtyElements[index].rebuild();
index += 1;
}
} finally {
for (Element element in _dirtyElements) {
element._inDirtyList = false;
}
_dirtyElements.clear();
}
}
复制代码
为啥要这样排?确保 parent 先于 child 被 rebuild,以避免 child 被重复 rebuild (由于 parent 在 rebuild 时会递归地 update child)。
_dirtyElements
中的元素依次调用rebuild
(第 14 行);_dirtyElements
(第 21 行)。所谓「Inactive Element」,是指 element 从「Element Tree」上被移除到 dispose 或被从新插入「Element Tree」间的一个中间状态。 设计 inactive 状态的主要目的是实现『带有「global key」的 element』能够带着『状态』在树上任意移动。
BuildOwer 负责对「Inactive Element」进行管理,包括添加、删除以及对过时的「Inactive Element」执行 unmount 操做。 关于「Inactive Element」的更多信息将在介绍 Element 时一块儿介绍。
BuildOwner 主要是用于收集那些须要 rebuild 的「Dirty Elements」以及处于 Inactive 状态的 Elements。
结束了!就是这么简单,下篇再见!