深刻淺出 Flutter Framework 之 BuildOwner

本文是『 深刻淺出 Flutter Framework 』系列文章的第二篇,對 BuildOwer 相關內容進行簡要地分析介紹,爲下一篇文章介紹 Element 做準備 (因爲篇幅緣由將其單獨提出來)。git

本文同時發表於個人我的博客github

本系列文章將深刻 Flutter Framework 內部逐步去分析其核心概念和流程,主要包括:post

Overview


BuildOwer在 Element 狀態管理上起到重要做用:ui

  • 在 UI 更新過程當中跟蹤、管理須要 rebuild 的 Element (「dirty elements」);
  • 在有「dirty elements」時,及時通知引擎,以便在下一幀安排上對「dirty elements」的 rebuild,從而去刷新 UI;
  • 管理處於 "inactive" 狀態的 Element。

這是咱們遇到的第一個 Owner,後面還有PipeOwnerthis

整棵「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」。遞歸

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 在下一幀須要作更新操做;
  • 將「Dirty Elements」加入到_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();
  }
}
複製代碼
  • 若有回調,先執行回調 (第 7 行);
  • 對「dirty elements」按在「Element Tree」上的深度排序 (即 parent 排在 child 前面) (第 10 行);

爲啥要這樣排?確保 parent 先於 child 被 rebuild,以避免 child 被重複 rebuild (由於 parent 在 rebuild 時會遞歸地 update child)。

  • _dirtyElements中的元素依次調用rebuild (第 14 行);
  • 清理_dirtyElements (第 21 行)。

Inactive Elements


所謂「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。

結束了!就是這麼簡單,下篇再見!

相關文章
相關標籤/搜索