My Introduction to Flutter

Spencer Dezart-Smith
CAMS Engineering
Published in
8 min readMay 25, 2020

--

Just prior to the beginning of Q2 I was asked if I would be interested in joining a new team focused on building the apps for our two products. I had been working on the web app of one of these products since its inception so I was excited by the opportunity to try something new. The apps would be built using Flutter. What is Flutter you ask???

Flutter is Google’s UI toolkit for building beautiful, natively compiled applications for mobile, web, and desktop from a single codebase.

This means that you can use one programming language and one codebase to create two different apps (for iOS and Android). Some of the benefits of using a cross platform development are:

  • Faster development. Faster release to market.
  • Only one codebase to build and maintain for both platforms.
  • Cheaper to produce.

I wasn’t completely new to this idea. One of my first programming jobs was building a health care app using React-Native. This was an exciting and rewarding project and was relatively easy to pick up as I was experienced in both Javascript and React.

Flutter is a whole new beast. The underlying language is Dart and the concept behind the SDK is using many, many, many composable widgets all together to build amazing products. Everything is a widget when it comes to Flutter just like everything is an object when we talk about Javascript.

Anyway, its been a couple weeks since this team was created and as we build we’re slowly working out what is best practice when it comes to writing code and also whats best for overall performance. I wanted to share some of the things I have learnt during this time.

A Simple App

So Dart is an object oriented language which means that things are generally represented using objects which hold both the data and the methods related to that object. Objects can inherit characteristics from other objects. We create a blueprint for these objects by using a class. Once the blueprint is written we can generate instances for the blueprint which in the case of Flutter, represents a widget!

Below is the generated project you get when you run flutter create . It is a small app which allows the user to increment a counter by 1 with each button press. Even though it’s small it does a great job at highlighting the two most important building blocks behind Flutters widgets which are the StatefulWidget and StatelessWidget.

Code sample of auto generated flutter app.
Auto generated Flutter app.

Stateful Widgets

Stateful widgets have their own internal state and the ability to manage that state. Every stateful widget comes with an accompanying state object. You can see this represented by the second class that is generated below the stateful widget. This private class extends Flutter’s State class. An instance of this private class is what’s returned from the createState method which creates the mutable state object for this widget at a given location in the tree. This state object is different to other widgets because it persists through rebuilds of the widget tree but more about that in a bit. The setState method is how a stateful widget updates its state and this is also what causes the build method to trigger a rebuild of the widget tree.

Stateless Widgets

Stateless widgets are ‘dumb’ widgets. They either consume data passed into them from a parent or they have their own data which is defined within the widget. They don’t have the ability to update or change this data.

In the example above there are two user created widgets, MyApp and HomePage . Each of these consume a handful of Flutter’s basic widgets such as Container and Text. All the widgets in the file are highlighted in yellow. As we spoke about classes earlier, all these yellow highlights are all just instances of their classes.

Too many widgets!!!

If you want to jump into building your first app check out the Flutter docs here. Now let’s look at some of the internal stuff that goes into making Flutter work!

Build Method

What makes a class a widget is the presence of the required build method. The build method is what is called upon instantiation of a widget and also whenever setState is called. It’s passed a BuildContext as a parameter which provides information about the widgets position in the tree. When this method is called it basically replaces the subtree below it with the widget and subtree it returns. This is how the widget screen is built and subsequently rebuilt throughout the life of the app session.

The Widget Tree

The widget tree is a representation of all the widgets you, as a developer, have defined to create the structure of your screen. Interestingly enough the widget tree is actually just a bunch of information about the widgets such as padding, alignment, colour etc and how they’re organised in relation to one another. When you start to learn about Flutter you hear the term ‘widget tree’ a lot but actually Flutter has two other trees that work alongside the widget tree to efficiently paint and repaint the UI as needed. The widget tree is something that rebuilds frequently.

The Render Tree

All of the widgets we have put together eventually form a series of pixels to be displayed on the screen. These groups of pixels actually correspond to objects called RenderObjects. These RenderObjects define the dimensions and position of the visual content and also identify the zones on the screen that may eventually be affected by gestures. It’s all of these RenderObjects combined that form the Render Tree. Below is a description for the Flutter docs:

The render tree is a data structure that stores the geometry of the user interface, which is computed during layout and used during painting and hit testing. Most Flutter developers do not author render objects directly but instead manipulate the render tree using widgets.

The Element Tree

The element tree is like the middleman between the first tree (widget) and the final tree (render). Whenever Flutter encounters a widget that it hasn’t seen before it creates an Element for it.

To each widget corresponds one element. Elements are linked to each other and form a tree. Therefore an element is a reference of something in the tree.

This element holds no actual configuration regarding the widget but rather it’s just like an object stored in memory that points to the widget. The element however does know what type of widget it’s pointing to and is also aware of its position in relation to other elements.

While the element points to the widget, if that widget is of a type that actually renders something to the screen then the element will also point to its corresponding render object.

The element tree is what does the comparing to the determine whether the render tree needs to update what’s painted on the screen.

Putting it all together

Representation of Flutter’s three trees

When setState is called within a stateful widget, that widget is marked as ‘dirty’ which triggers a call to that widgets build method. This in turn calls all the build methods of all the widgets nested inside that widget unless they’ve been marked as const. Widgets are actually immutable therefore this rebuilding process recreates that section of the tree completely with new instances created to replace the previous ones.

Each corresponding element looks at the new configuration its pointing to and compares it to the information it currently holds regarding that widget and also its position in relation to its neighbouring elements. If the type and position are the same then it simply updates its reference to point to the newly created widget. Otherwise that part of the element tree and all of its children detach and are rebuilt as each new widget is encountered.

Note: You can also see the State object sitting outside of the stateful element. That is because it lives independent of the stateful element and persists throughout the life of the widget.

Second note: In cases of lists you’re able to provide a key to make sure that the widgets are updated correctly.

A Couple Best Practices

There have been a couple of practices that my team have been able to establish early on in relation to these subjects. Not only do these keep the code clean and readable but also helps to improve performance of your app. There are so many more that you can read up on also…

Extracting Widgets

If you read through the Flutter style guide you will see that there is a preference for your maximum line length to be just 80 characters 😱 This actually makes a lot of sense after coding in Flutter for more than 10 minutes. The widget tree can get very big, very fast. Extracting widgets into their own classes is a good practice to make the code easier to digest but also it isolates sections giving them their own build methods which can help with performance optimisations also. Limiting the characters to 80 is a constant reminder to extract wherever possible.

Declare Const Widgets Where Possible

Even though the widget tree rebuilding is just rebuilding configurations rather than the entire UI, it still makes sense to avoid unnecessary rebuilds to save processing power. A great way to do this is by declaring widgets that know their data values at compilation as const widgets. In theory all Stateless widgets can be thought of as const widgets. When prefaced with const in the widget tree, the widget will never have its build method called again.

Avoid unnecessary rebuilds by using const widgets when data is known during compilation

Conclusion

After just a couple of weeks working with Flutter I am excited by what I have learnt and am super pumped to learn more and share more about the journey in the coming months. If you want to dive deeper into some of these topics, check out the links below!

--

--