This article, the second in the “Flutter Framework in A nutshell” series, provides a brief overview of BuildOwer in preparation for the next article on Element (which is mentioned separately for space reasons).

This article is also published on my personal blog

This series of articles explores the core concepts and processes of the Flutter Framework step by step, including:

  • “Widgets of the Flutter Framework”
  • “BuildOwner of the Flutter Framework”
  • Elements of the Flutter Framework
  • “PaintingContext of the Flutter Framework”
  • “Layer of the Flutter Framework”
  • PipelineOwner of the Flutter Framework
  • RenderObejct of the Flutter Framework
  • “Binding of the Flutter Framework”
  • “The Rendering Pipeline of the Flutter Framework”
  • “Custom Widgets from the Flutter Framework”

Overview


BuildOwer plays an important role in Element state management:

  • Track and manage rebuild elements (” dirty Elements “) during UI updates
  • Notifying the engine of “dirty Elements” in time to arrange rebuild to “Dirty Elements” on the next frame to refresh the UI;
  • Manage Elements that are in the “inactive” state.

This is the first Owner we have, followed by PipeOwner.

The entire “Element Tree” shares the same BuildOwer instance (global) and is passed by the parent to the child Element during the Element mounting process.

@mustCallSuper
void mount(Element parent, dynamicnewSlot) { _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;
}
Copy the code

This is the mount method of the Element base class, and line 8 assigns the parent. Owner to the child.

BuildOwer instance by WidgetsBinding responsible for creating and assigned to the root node of the Element “Tree” RenderObjectToWidgetElement, then as the “Tree” Element to create step by step to child nodes. (The detailed process will be analyzed in the following article)

In general, it is not necessary for us to instantiate BuildOwer manually, unless we need off-screen immersion (in which case, we need to build an off-screen Element tree).

BuildOwer has two key member variables:

final _InactiveElements _inactiveElements = _InactiveElements();
final List<Element> _dirtyElements = <Element> [];Copy the code

Their name clearly states their purpose: they are used to store “Inactive Elements” and “Dirty Elements” that are collected, respectively.

Dirty Elements


So how does BuildOwer collect Dirty Elements? For an element that needs to be updated, the element.markNeedsbuild method is first called, as in the state.setState method described earlier:

void setState(VoidCallback fn) {
  final dynamic result = fn() as dynamic;
  _element.markNeedsBuild();
}
Copy the code

As follows, Element. The BuildOwer markNeedsBuild call. ScheduleBuildFor method:

void markNeedsBuild() {
  if(! _active)return;

  if (dirty)
    return;

  _dirty = true;
  owner.scheduleBuildFor(this);
}
Copy the code

BuildOwer. ScheduleBuildFor method did two things:

  • callonBuildScheduledThis method (which is actually a callback) tells the Engine that it needs to update on the next frame.
  • Add “Dirty Elements” to_dirtyElementsIn the.
void scheduleBuildFor(Element element) {
  assert(element.owner == this);
  onBuildScheduled();

  _dirtyElements.add(element);
  element._inDirtyList = true;
}
Copy the code

After that, WidgetsBinding. DrawFrame calls BuildOwer. BuildScope when a new frame is drawn:

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(); }}Copy the code
  • If there is a callback, execute the callback first (line 7);
  • Sort “dirty Elements” by depth on the “Element Tree” (i.e. parent before child) (line 10);

Why are we doing this? Make sure that the parent is rebuilt before the child so that the child is not rebuilt repeatedly (because the parent recursively updates the child when it is rebuilt).

  • right_dirtyElementsIs called in turnrebuild(Line 14);
  • Clean up the_dirtyElements(Line 21).

Inactive Elements


An Inactive Element is an Element that is removed from an Element Tree to an intermediate state between dispose or re-inserted into an Element Tree. An inactive state is designed so that “Elements with” global key “can move around the tree with” status “.

BuildOwer manages Inactive Elements, including adding, deleting, and unmounting expired Inactive elements. More information about the “Inactive Element” will be covered in the introduction to Element.

summary

BuildOwner collects Dirty Elements that need to be rebuilt and Elements that are in Inactive state.

Is over! It’s that simple. See you next time!