How Flutter renders Widgets

Manabie Tech-Product Blog
Manabie
Published in
4 min readJan 16, 2020

Introduction

Hey! Welcome back to the Flutter “game”. I’m going to play with you the next stage in Flutter world, which is “Why Flutter can render so fast?”, and the related notions are: Widget, Element and Render Object. Do not have a glimpse of what they are? These might be tricky for a new player. Let’s figure them out!

Notion

A very boring part but we can’t upgrade the level without it.

What is a Widget?

Everything is widget”. That’s true. A very common ordinary saying when you first step in Flutter world. Let’s see what Flutter team tells us about Widget:

“A widget is an immutable description of part of a user interface”

When you read the Flutter source code, you will notice the following definition of the Widget class.

Look! There is an annotation “@immutable” on the far upright corner. This is very important. All properties in the Widget have to be FINAL. So once instantiate, the inner properties of Widget can’t be changed.

“Hmm, I need a clue?”

In fact, UIs are not immutable. Therefore, how does Flutter manage the state of UI? How does Flutter represent change?

Flutter has three trees: the Widget tree, the Element tree, and the RenderObjects Tree. These trees have different concepts; by combining these three together, we will optimize the rendering performance of a UI as much as possible.

“I know the Widget but what is Element and Render Object?”

What is an Element?

Document again: “An instantiation of a Widget at a particular location in the tree.”

It’s the mutable piece of the tree which manages updating and changing of UI. You can think of it as managing the lifecycle of widgets. Every Element holds a reference to a Widget and Render Object. That’s all. Keep it simple enough!

What is a Render Object?

When Flutter draws your UI, it does not look at the tree of Widgets, but looks at the Render Objects’ one which controls all of the sizes, layouts and keeps all logic for painting the actual widget. That’s the reason why Render Object is very expensive to instantiate.

To better visualize these three trees, let’s look at the following simple widget:

When your app starts,

  1. Flutter will go through your widgets and create the Widget tree.
  2. Corresponding to the Widget tree, Flutter creates the Element tree in which each Element object is created by calling createElement() on the widget.
  3. Each render object will be created when Element calls createRenderObject().

This diagram indicates how Widget, Element, and Render Object relates to one another.

That is it for Notions! Now let’s code to see how fast Flutter could be.

Here is what we are going to do: we try to change the value of the Text widget when tapping Change button and let’s see what we have in Flutter Inspector.

Result:

When running the app, we need to only focus on the text’s value and instance Id of Render Object.

After we change:

It looks the same, so what’s happening here? Because the Render Object is quite expensive to instantiate, keeping or recycling it is a more sensible option. How can we do that? We will use Element. It acts as the glue between Widget and Render Object which takes responsibility for comparing the runtime type of both. If they have the same type, Render Object does not need to recreate; we just update the property value and updateRenderObject() will be triggered. If not, the Tree from Element and Render Object will throw it away and create a new one.

In reality, when developing your app, you will have a hundred widgets, and in-depth layouts; therefore, rebuilding the entire tree is very expensive. We suggest making these three concepts on Flutter to minimize the processing, thus gaining more optimal performance when UI changes.

Conclusion

This is our recap on how Flutter renders Widgets, in simpler terms. We hope this guideline may be useful to all of you readers, and we are more than eager to hear your feedback! Thank you for reading!

--

--