“This is the second day of my participation in the First Challenge 2022.

There are three trees in the Flutter rendering process: Widget tree, Render tree and Element tree.

The Widget tree

What is a Widget tree? In Android Studio, you can see what a Widget tree looks like after a page is rendered. Let’s take a look at the Widget tree in the chat interface for example.

Click on the Flutter Inspector tool on the right side of Android Studio to display the hierarchy of the Widget tree on the current page:

Note that the rendering engine of Flutter does not render the Widget tree directly, because it would be very costly to re-render the entire Widget once the build method is executed (widgets change frequently).

Render tree

The RenderObject tree, which contains RenderObject objects, is used by the **Flutter engine. Not all widgets generate RenderObjects, such as Containers; Renderobjects are generated only if they eventually inherit from RenderObjectWidget, such as Column;

RenderObjectWidget (RenderObjectWidget) RenderObjectWidget (RenderObjectWidget)

abstract class RenderObjectWidget extends Widget {
  const RenderObjectWidget({ Key? key }) : super(key: key);

  @override
  @factory
  RenderObjectElement createElement();

  @protected
  @factory
  RenderObject createRenderObject(BuildContext context);

  @protected
  void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }

  @protected
  void didUnmountRenderObject(covariant RenderObject renderObject) { }
}
Copy the code

RenderObjectWidget has two abstract methods createElement() and createRenderObject(); RenderObjectWidget (RenderObjectWidget); RenderObjectWidget (RenderObjectWidget);

  • A subclassMultiChildRenderObjectWidgetImplemented in thecreateElementMethods:
@override
MultiChildRenderObjectElement createElement() => MultiChildRenderObjectElement(this);
Copy the code

While MultiChildRenderObjectElement inherited from RenderObjectElement;

  • A subclassStackImplemented in thecreateRenderObjectMethods:
@override
RenderStack createRenderObject(BuildContext context) {
  assert(_debugCheckHasDirectionality(context));
  return RenderStack(
    alignment: alignment,
    textDirection: textDirection ?? Directionality.maybeOf(context),
    fit: fit,
    clipBehavior: overflow == Overflow.visible ? Clip.none : clipBehavior,
  );
}
Copy the code

This method creates a RenderStack that inherits from RenderObject based on the RenderStack inheritance chain; RenderObjectWidget creates both an Element tree and a RenderObject tree.

The Element tree

The StatelessWidget directly inherits from the Widget. There is no RenderObject inside it, but an Element object inside it:

In the Widget’s source code, there is an abstract method called createElement(), which means that all objects inherited from the Widget have an Element object: the Widget tree corresponds to the Element tree.

Again, the same method is implemented in StatefulWidget:

Let’s make a breakpoint in the createElement method in the StatefulWidget and run the project in Debug mode to see what the breakpoint looks like:

We see that the first call to createElement from the start of the project is the MaterialApp component; Now this is the MaterialApp;

So, if we put the breakpoint in the StatelessWidget, let’s see what happens:

This is going to point to MyApp; Our main.dart file looks like this:

At this point, let’s step through:

At this point the code will execute to:

Here the mount method will be executed next. Let’s take a look at the mount method. We’ll focus on the comment:

From the comment we know that the mount method is called when a new Element is added to the Element tree. Since widgets correspond to elements one by one, we can also understand that the mount method is called when a Widget is created.

The new Element is different from the old one;

We already know that StatefulWidget and StatelessWidget don’t have RenderObject objects, so let’s look at the mount method for components that have RenderObject objects:

Step breakpoint execution:

Next break point into mount method:

We find that the mount method now calls super.mount. We enter the super.mount method:

Mount RenderObjectElement (RenderObjectElement); create RenderObject (RenderObjectElement);

Then we can draw a conclusion:

In the rendering process of Flutter, the object in the Render tree is finally rendered. When a Widget is created, the createElement method creates an Element to add to the Element tree, and the mount method is executed. If there is a RenderObject(Element inherits from RenderObjectElement), the createRenderObject tree will be created in the mount method. If there is a RenderObject tree, the createRenderObject tree will not be created.