background

Dart’s main method calls the runApp method to pass the Widget that the developer wrote into Flutter. When compiled and run, the Widget will have the desired effect. We wondered, what’s going on behind the scenes? Or, what is the core mechanism of Flutter that you often hear about? So let’s talk about it.

Flutter program entry

The entry point of a Flutter App written by the developer is usually in the main method, inside which the widgets of our entire App are added and run by calling the runApp method. The runApp method is implemented as follows:

void runApp(Widget app) { WidgetsFlutterBinding.ensureInitialized() .. scheduleAttachRootWidget(app) .. scheduleWarmUpFrame(); }Copy the code

The three lines above represent the core three steps of Flutter initiation (cascade operator calls)

  • WidgetsFlutterBinding initialization (ensureInitialized)
  • Schedule and bind root nodes to create three core trees (scheduleAttachRootWidget(app))
  • ScheduleWarmUpFrame ()

WidgetsFlutterBinding instance and initialization

The source code is as follows:


This is the glue that binds the framework to the Flutter engine.

class WidgetsFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding, ServicesBinding, PaintingBinding, SemanticsBinding, RendererBinding, WidgetsBinding {
  static WidgetsBinding ensureInitialized() {
    if (WidgetsBinding.instance == null)
      WidgetsFlutterBinding();
    return WidgetsBinding.instance!;
  }
}
Copy the code

Analysis of the source code, you can find. This is the glue that binds the framework to the Flutter engine. The WidgetsFlutterBinding class Bridges the Widget framework and the Flutter engine. It is also the core of the application layer of Flutter. WidgetsFlutterBinding inherits from BindingBase and comes with a large number of mixin classes. Using the ensureInitialized() method we get a WidgetsFlutterBinding instance of the global singleton, and a bunch of XXXBindings for the mixin are also instantiated.

InitInstances () is called in the constructor of the BindingBase abstract class, and the XxxBinding instantiation of all mixins is in its own initInstances() method.

  • WidgetsFlutterBinding: The core bridge body of the Widget framework and the Flutter engine, which is globally unique to the Flutter app.

  • BindingBase: Binding service abstract class.

  • GestureBinding: Binds gesture events. Handlepointerdatapacket = handlePointerDatapacket = handlePoInterDatapacket; The Window instance is a bridge between the Framework layer and the Engine layer for handling screen events.

    void initInstances() {
      super.initInstances();
      _instance = this;
      window.onPointerDataPacket = _handlePointerDataPacket;
    }
    Copy the code
  • SchedulerBinding: draws the binding classes related to the scheduler, and debuts the drawing process duration when the Flutter is compiled.

  • ServicesBinding: The Flutter system platform listens for binding classes. Platform communicates with the Flutter layer. The registration also listens for the application’s declaration cycle.

  • PaintingBinding: a binding class that draws a preheated cache. Importantly, image caching is tied in.

    void initInstances() { super.initInstances(); _instance = this; _imageCache = createImageCache(); shaderWarmUp? .execute(); }Copy the code
  • SemanticsBinding: Binder binding class between the semantic tree and the Flutter engine.

  • RendererBinding: A binding class between the render tree and the Flutter engine that holds the root node of the render tree. RenderView is the root node of the RenderObject rendering tree.

    void initRenderView() { assert(! _debugIsRenderViewInitialized); assert(() { _debugIsRenderViewInitialized = true; return true; } ()); renderView = RenderView(configuration: createViewConfiguration(), window: window); renderView.prepareInitialFrame(); }Copy the code
  • WidgetsBinding: Binder binding class between the Widget tree and the Flutter engine.

From the runApp startup method of the Flutter above, we can see that these XXxbindings assume the role of a bridge association binding, as follows:

Since we will focus on the main process mechanism of Flutter startup and the creation process of three trees, we need to focus on the initInstances() methods of RendererBinding and WidgetsBinding classes as follows:

// The glue between The render tree and The Flutter engine. Render binding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, SemanticsBinding, HitTestable { @override void initInstances() { super.initInstances(); _instance = this; /* Create a class that manages the rendering pipeline and provides interface calls to trigger rendering */ _pipelineOwner = PipelineOwner(onNeedVisualUpdate: ensureVisualUpdate, onSemanticsOwnerCreated: _handleSemanticsOwnerCreated, onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed, ); /* Window change related callback listener */ window.. onMetricsChanged = handleMetricsChanged .. onTextScaleFactorChanged = handleTextScaleFactorChanged .. onPlatformBrightnessChanged = handlePlatformBrightnessChanged .. onSemanticsEnabledChanged = _handleSemanticsEnabledChanged .. onSemanticsAction = _handleSemanticsAction; /* Create the RenderView object, which is the root node of the RenderObject rendering tree */ initRenderView(); . } /// Creates a [RenderView] object to be the root of the /// [RenderObject] rendering tree, and initializes it so that it /// will be rendered when the next frame is requested. /// /// Called automatically when the binding is created. Create the render tree root object void initRenderView() {...... RenderView = renderView (configuration: createViewConfiguration(), window: window); renderView = renderView (configuration: createViewConfiguration(), window: window); renderView.prepareInitialFrame(); RenderView => _pipelineowner.rootNode! RenderView => _pipelineowner.rootnode! as RenderView; /* Define renderView's set method, which instantiates assignments in initRenderView() to _pipelineowner.rootNode. */ set renderView(RenderView value) { assert(value ! = null); _pipelineOwner.rootNode = value; } ## WidgetsBinding class // The glue between The widgets layer and The Flutter engine WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureBinding, RendererBinding, SemanticsBinding { @override void initInstances() { super.initInstances(); _instance = this; assert(() { _debugAddStackFilters(); return true; } ()); The BuildOwner class keeps track of which Widgets need to be rebuilt and handles other tasks for the Widget tree, such as managing inactive Widgets, debugging mode triggering rebuild, etc. */ _buildOwner = BuildOwner(); /* Callback method assignment, called when the first buildable element is marked dirty. */ buildOwner! .onBuildScheduled = _handleBuildScheduled; /* Callback method assignment, called when local configuration changes or AccessibilityFeatures changes. */ window.onLocaleChanged = handleLocaleChanged; window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged; SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation); . }Copy the code

Analyze the initialization process above, and focus on RendererBinding and WidgetsBinding initialization methods. RenderView in RendererBinding is the root node of the RenderObject rendering tree. We can get the following flow chart: