After reading the previous post in this series, you may be wondering how to actually rebuild widgets and how much performance is consumed during this process. To answer all of these questions, you need to understand the Element Tree, Widget Tree, and Render Tree. You also need to understand how Flutter executes the build(){…} method and how it rebuilds or modifies information on the screen.

So what really happens?

Flutter does not redraw or recreate the entire UI every time the build(){…} method is called. Let’s discuss this in more detail.

• The default configuration for applications created in Flutter is 60FPS (Frames Per Second). This means that the Flutter system redraws the interface 60 times per second.

• This only becomes inefficient when Flutter has to recalculate the entire layout 60 times per second.

• When Flutter first draws something on the screen, it needs to calculate the position, color, text, and other attributes of every component on the screen. In other words, Flutter needs to edit every pixel on the screen when drawing the initial interface.

• In the next edit/drawing, if nothing has changed, Flutter will retrieve the old information and draw it on the screen extremely quickly and efficiently to update the UI.

• Therefore, the speed of redrawing is not a problem, and it only becomes a problem when Flutter needs to recalculate everything on the screen every time it updates.

• In this article, let’s take a detailed look at whether Flutter recalculates everything every time the build(){…} method is called!

Widget Tree

• Simply put, the Widget Tree is all the widgets used to construct the application. In other words, the widget tree is created from the code you write.

• It can be fully managed by declaring widgets and nesting them together to create the desired layout.

• When the build(){…} method is called, the Widget Tree is built in Flutter. The Flutter system handles this part independently.

• Not just displayed on the screen, but instead instructs Flutter what to draw on the next screen. The Widget tree is frequently rebuilt.

Element Tree

• The Element Tree is bound to the Widget Tree and represents the actual displayed objects/elements and their set-up information. It is rarely rebuilt.

• The Element Tree is managed differently and not rebuilt even when the build method is called.

• For each Widget in the Widget Tree, Flutter automatically creates its corresponding element. This is done immediately when Flutter first processes the Widget.

• Here an element can be seen as an object managed by Flutter in memory and is associated with a Widget in the Widget Tree.

• An element holds only one reference to a Widget (in the Widget Tree) that has a terminal interface parameter.

Render Tree

• The Render Tree represents the elements/objects that are displayed on the screen.

• The Render Tree is also rarely rebuilt!

• The Element Tree is also bound to the Render Tree. Elements in the Element Tree refer to the render objects that are displayed on the screen.

• When Flutter detects an element that has not been previously rendered, it references the Widget in the Widget Tree and sets it up within the element tree.

• Flutter also has a layout phase where it calculates and retrieves things such as screen space, orientation, size, etc. Additionally, there is a separate phase where listeners are set up in Widgets to manipulate events.

In simple terms, elements that have not been rendered are rendered on the screen. A pointer is created in the later Element (in the element tree) to the Render Object (in the Render Tree) on the screen. There is also a pointer to the configuration information of this element in the Widget (in the Widget Tree).

How Flutter Implements build(){…}

The build() method is called by Flutter every time there is a change in state. Basically, there are two conditions that trigger Flutter’s rebuild.

The first case is when the setState(){…} method is called in a Stateful Widget. Whenever setState(){…} is automatically called, the build(){…} method is immediately called as well.

The second case is when the virtual keyboard is displayed or hidden every time the MediaQuery or Theme.of(…) command is called. Whenever these data are changed, the build(){…} method is automatically triggered.

To be precise, calling setState(){…} marks the corresponding element as dirty. In the next rendering that occurs 60 times per second, Flutter checks the new configuration information created by the build(){…} method and updates the screen.

All the widgets nested inside the Widget marked as dirty are created as new widget/dart objects. Therefore, a new Widget Tree corresponding to the new version of all these widgets is created.

Since the Widget Tree is immutable, the properties of existing widgets cannot be changed but can be overridden with new widgets. This method is heavily implemented by Flutter because it allows changes to be more efficiently detected when objects are modified.

For example, a Stateful Widget is displayed on the screen with a Child Widget nested in the text (Text Widget). The Text Widget is a Stateless Widget that displays text on the screen based on the state of the parent widget.

When the state changes, the displayed text immediately changes from True to False or vice versa. GestureDetector is the parent of the Text Widget. As its parent, GestureDetector handles state changes by calling setState(){…} method.

When the Text Widget is clicked, the parent handles the setState() immediately. Therefore, the TestWidget is marked as dirty. When the build(){…} method is called in Flutter, a new Widget Tree is created.

Next, the new Widget Tree information is compared with the actual content displayed on the screen. Flutter detects that only the text inside the Text Widget has changed without changing the color of the container. Therefore, the Render Tree displays only the text inside the Text Widget instead of all the content.

This is why Flutter works efficiently. There is no need to reconstruct the Element Tree when the build(){…} method is called. Only the Widget Tree is reconstructed, and the Element Tree is updated to reference the new Widget Tree. Then, it checks if there is any new information for the Widget. If there is new information, it passes the information to the Render Object to draw the changes on the screen.

If you want to read more about the logic render, it is recommended to read this article from the official Flutter documentation.

Example:

A Stateful Widget is displayed on the screen. Nested within the text, there is a child widget (Text Widget). The Text Widget is a Stateless Widget that displays text on the screen based on the state of its parent widget.

When the state changes, the text displayed immediately changes from True to False, or vice versa. GestureDetector is the parent of the Text Widget. As its parent, GestureDetector handles the state change by calling setState() {…} method.

When Text Widget is clicked, its parent processes setState, marking TextWidget as dirty. When the build() method is called in Flutter, a new Widget Tree is created. Then, the new Widget Tree information is compared to the actual content displayed on the screen.

Flutter detects that only the text within the Text Widget has changed without changing the color of the container. Therefore, the Render Tree displays only the text inside the Text Widget and not all contents

This is why Flutter operates efficiently. When the build() method is called, there is no need to rebuild the Element Tree. Only the Widget Tree is rebuilt, and the Element Tree is updated with a reference to the new Widget Tree. Then, Flutter checks if there is any new information about the widget. If there is new information, it passes the information to the Render Object, which can draw changes on the screen.

If you want to learn more about Logic Render, it is recommended to read this article from the official Flutter documentation.

Quick Comment:

Some widgets do not change even after rebuilding the Widget Tree, which can further optimize the build process. To let Flutter know that these widgets do not need to be rebuilt, the const keyword can be used in front of them. The goal is to completely skip the reconstruction of those widgets by Flutter.

Example:

In the above example, the const keyword is used to skip the reconstruction of the Padding widget. Also, the build process can be optimized by carefully dividing large widgets into smaller ones.

Conclusion:

In this article, we have explained in detail about Flutter’s specifications. We hope that you have understood what is happening behind the scenes during the Widget reconstruction process.

Japanese Blog

INTS Inc. Development Division, Hai Ain

• AI

• Business

• Technology

• Uncategorized

• Offshore development

• Chatbots

• Programming

• Artificial Intelligence

• Technology

• Development