the Flutter building process

Flutter is the new trending for mobile development, and the UI is fluent and coding is made efficient using convenient tools like hot-reload and dart devtools.

But the other day when I was build a Flutter app for the company, a strange bug has occurred. I built a user login page which was itself pushed by the navigator from a user info tab. When typing into the password field, the system keyboard has to pop up, and that causes the pushed login page’s state to be recreated and the password I stored inside the model class was lost because the whole model was recreated. Eventually it was solved by lifting the model up to the pushing widget, but it made me curious about the flutter building process.

By reading flutter’s technical blogs, I found that building process begins with the system vsync siganl which was handled by flutter engine’s handleDrawFrame method.

src/foundation/bindings.dart

/// A number of additional bindings are defined as extensions of [BindingBase],
/// e.g., [ServicesBinding], [RendererBinding], and [WidgetsBinding]. Each of
/// these bindings define behaviors that interact with a [ui.Window], e.g.,
/// [ServicesBinding] registers a [ui.Window.onPlatformMessage] handler, and
/// [RendererBinding] registers [ui.Window.onMetricsChanged],
/// [ui.Window.onTextScaleFactorChanged], [ui.Window.onSemanticsEnabledChanged],
/// and [ui.Window.onSemanticsAction] handlers.

The bindings class are indeed handlers for different platform events, here we focus on WidgetBinding which handles the system v-sync call.

src/widgets/binding.dart

class WidgetsFlutterBinding extends BindingBase with GestureBinding, ServicesBinding, SchedulerBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding 

WidgetsFlutterBinding is the concrete class which was instantiated during Flutter startup. It is the glue layer between Flutter engine and Flutter framework.

mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding

the on keyword ensures that only certain types can use the mixin.

in this mixin there is the drawFrame method where it all begins.

when drawFrame is signaled by the Flutter engine’s handleDrawFrame method. It calls the buildOwner’s buildScope method.

src/widgets/framework.dart

 /// The [BuildOwner] in charge of executing the build pipeline for the
  /// widget tree rooted at this binding.

in the BuildOwner class, there maintained two lists of elements,

  1. _dirtyElements <Element>[]
  2. _inactiveElements = _InactiveElements()

When a element is no longer in the element tree, it is moved to the inactiveElements list, and later purged by the framework.

when app state changes or user interacted with the interface, elements are marked as dirty using its BuildOwner’s scheduleBuildFor(Element element) method and therefore in the _dirtyElements tree, then in each build cycle the dirty elements are rebuilt using the new state.

when BuildOwner’s buildScope method is called by the binding’s drawFrame, it starts the rebuilding process, which first sorts the dirty elements and call rebuild on each dirty element. After it’s all done it clears the dirty elements list.

And that is what I found about the Flutter building process by reading the source code from Flutter framework. If you have any corrections or ideas, please comment below, Thank you.