## 构建(build)阶段
结合上文 build阶段主要再`buildOwner.buildScope(renderViewElement)`;
~~~
void buildScope(Element context, [VoidCallback callback]) {
try {
_scheduledFlushDirtyElements = true;
_dirtyElements.sort(Element._sort);
_dirtyElementsNeedsResorting = false;
int dirtyCount = _dirtyElements.length;
int index = 0;
while (index < dirtyCount) {
try {
_dirtyElements[index].rebuild();
} catch (e, stack) {
...
}
index += 1;
}
} finally {
for (Element element in _dirtyElements) {
element._inDirtyList = false;
}
_dirtyElements.clear();
_scheduledFlushDirtyElements = false;
_dirtyElementsNeedsResorting = null;
}
}
~~~
还记得在调度帧之前会把需要更新的`Element`标记为“脏”(dirty)并放入`BuildOwner`的`_dirtyElements`列表。这里Flutter会先按照深度给这个列表排个序。因为`Element`在重建的时候其子节点也都会重建,这样如果父节点和子节点都为“脏”的话,先重建父节点就避免了子节点的重复重建。
排完序就是遍历`_dirtyElements`列表。依次调用`Element.rebuild()`。这个函数又会调用到`Element.performRebuild()`。我们之前介绍`Element`的时候说过`performRebuild()`由其子类实现。
## rebuild
`Element.rebuild()`
~~~
void rebuild() {
if (!\_active || !\_dirty)
return;
performRebuild();
}
~~~
`performRebuild()`是在`Element`的父类`ComponentElement`里:
~~~
void performRebuild() {
Widget built;
built = build();
try {
_child = updateChild(_child, built, slot);
} catch (e, stack) {
...
}
}
~~~
## Element.updateChild()
~~~
Element updateChild(Element child, Widget newWidget, dynamic newSlot) {
if (newWidget == null) {
if (child != null)
deactivateChild(child);
return null;
}
if (child != null) {
if (child.widget == newWidget) {
if (child.slot != newSlot)
updateSlotForChild(child, newSlot);
return child;
}
if (Widget.canUpdate(child.widget, newWidget)) {
if (child.slot != newSlot)
updateSlotForChild(child, newSlot);
child.update(newWidget);
return child;
}
deactivateChild(child);
}
return inflateWidget(newWidget, newSlot);
}
~~~
函数`updateChild()`比较重要,用来更新一个孩子节点。更新有四种情况:
* 新`Widget`为空,老`Widget`也为空。则啥也不做。
* 新`Widget`为空,老`Widget`不为空。这个`Element`被移除。
* 新`Widget`不为空,老`Widget`为空。则调用`inflateWidget()`以这个`Wiget`为配置实例化一个`Element`。
* 新`Widget`不为空,老`Widget`不为空。调用`update()`函数更新子`Element`。`update()`函数由子类实现。
## update
`StatefulElement`和`StatelessElement`的`update()`函数最终都会调用基类`Element`的`rebuild()`函数。
`RenderObjectElement`的`update()`。
~~~
void update(covariant RenderObjectWidget newWidget) {
super.update(newWidget);
widget.updateRenderObject(this, renderObject);
_dirty = false;
}
~~~
更新只是调用了一下`RenderObjectWidget.updateRenderObject()`。这个函数我们之前介绍过,只是把新的配置设置到现有的`RenderObject`上。
StatelessElement的update实现
~~~
class StatelessElement extends ComponentElement {
@override
Widget build() => widget.build(this);
@override
void update(StatelessWidget newWidget) {
super.update(newWidget);
_dirty = true;
rebuild();
}
}
~~~
StatefulElement的update实现
~~~
class StatefulElement extends ComponentElement {
@override
void update(StatefulWidget newWidget) {
super.update(newWidget);
final StatefulWidget oldWidget = _state._widget;
// Notice that we mark ourselves as dirty before calling didUpdateWidget to
// let authors call setState from within didUpdateWidget without triggering
// asserts.
_dirty = true;
_state._widget = widget;
rebuild();
}
}
~~~
而LeafRenderObjectElement没有实现update,不会rebuild(()
因此假设我们有这样的一个三层element tree进行更新重建。
~~~
父(StatefulElement)
子(StatefulElement)
孙(LeafRenderObjectElement)
~~~
那么从父节点开始,调用顺序如下:
父.rebuild()--->父.performRebuild()--->父.updateChild()--->子.update()--->子.rebuild()--->子.performRebuild()--->子.updateChild()--->孙.update()。
可见构建(build)过程是从需要重建的`Element`节点开始一层层向下逐个更新子节点。直到遇到叶子节点为止。