本文是『 深刻淺出 Flutter Framework 』系列文章的第二篇,對 BuildOwer 相關內容進行簡要地分析介紹,爲下一篇文章介紹 Element 做準備 (因爲篇幅緣由將其單獨提出來)。git
本文同時發表於個人我的博客github
本系列文章將深刻 Flutter Framework 內部逐步去分析其核心概念和流程,主要包括:post
BuildOwer
在 Element 狀態管理上起到重要做用:ui
這是咱們遇到的第一個 Owner,後面還有
PipeOwner
。this
整棵「Element Tree」共享同一個BuildOwer
實例 (全局的),在 Element 掛載過程當中由 parent 傳遞給 child element。spa
@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。設計
BuildOwer
實例由WidgetsBinding
負責建立,並賦值給「Element Tree」的根節點RenderObjectToWidgetElement
,此後隨着「Element Tree」的建立逐級傳遞給子節點。(具體流程後續文章會詳細分析) 通常狀況下並不須要咱們手動實例化BuildOwer
,除非須要離屏沉浸 (此時須要構建 off-screen element tree)code
BuildOwer
兩個關鍵成員變量:排序
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。
結束了!就是這麼簡單,下篇再見!