preface

In the Flutter knowledge system, Widget, Element and RenderObject are three important classes. There are a lot of knowledge points in it, and today I will focus on sharing with you how these three trees are constructed.

Class inheritance

Just list a few that are relevant to this article

The Widget:

As you can see from the figure above, the Widget base class is definedcreateElement()The override method constructs different Element classes. It is also important to note that only the RenderObjectWidget class is definedcreateRenderObject()Function, so any object that can construct a renderObject must be a subclass of it; Second, you can see that only the StatelessWidget class has itbuild()Function (StatefulWidget is called by statebuild()), which will be discussed later.

Element:

As you can see here, the classes of Element and Widget are basically corresponding

RenderObject:

Widget/Element/RenderObject initialization process, as well as their relationship

Dart’s entry function is positioned first:

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

WidgetsFlutterBinding Flutter frame and engine layer is mainly responsible for connections, through our incoming widgets to generate Wiget Elemtn/RenderObject tree, This class has two important attributes: the root of the Render Tree and the root of the Element Tree. And how to initialize the root node initially:

RenderObjectToWidgetAdapter _renderViewElement / / inherited from RenderObjectWidget RenderView RenderView / / inherited from RenderObject / / Initialize rootElement and rootWidget and bind rootRenderObject to rootElement. Attach Widget(app) to rootWidget void attachRootWidget(Widget rootWidget) {_readyToProduceFrames = true; _renderViewElement = RenderObjectToWidgetAdapter<RenderBox>( container: renderView, debugShortDescription: '[root]', child: rootWidget, ).attachToRenderTree(buildOwner, renderViewElement as RenderObjectToWidgetElement<RenderBox>); }Copy the code

Next, let’s take a look at the class definition of RenderObjectToWidgetAdapter:

class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget { final Widget child; final RenderObjectWithChildMixin<T> container; RenderObjectWidget { RenderObjectToWidgetAdapter({ this.child, this.container, this.debugShortDescription, }) : super(key: GlobalObjectKey(container)); // Make yourself an argument to the element constructor, Generate a element instances @ override RenderObjectToWidgetElement < T > createElement method () = > RenderObjectToWidgetElement < T > (this); @override RenderObjectWithChildMixin<T> createRenderObject(BuildContext context) => container; RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [RenderObjectToWidgetElement < T > element if element (= = null) {... / / instantiate an element = createElement method without rootElement (); / / With the mount function, Instantiate a rootRenderObject and mount it to rootElement element. Mount (null, } else {...} // return rootElement to render Viewelement;}Copy the code

Through the above code can know, RenderObjectToWidgetAdapter class is an adapter, through it constructed the whole tree

Let’s look at how the root node is initialized, briefly as follows:
  1. RenderObjectToWidgetAdapter through the constructor for the external incoming widgets and renderObject (rootRenderObject), initialize a rootWidget instance of the object, and the external incoming widget mounted to the root On the Widget
  2. Through RenderObjectToWidgetAdapter instance of the objectcreateElement()Create a RenderObjectToWidgetElement instance objects as rootElement, hold rootWidget and rootRenderObject rootElement.
  3. RootElement callsmount()The function, in the parent implementation, gets the widget held by the current rootElement, called by rootWidget, through a getter methodcreateRenderObject()Method returns the renderObject obtained externally and mounted to the rootElement as the rootRenderObject
  4. Through the above steps, the root nodes of the three trees are created and referenced to each other
How the child node is initialized is briefly as follows:
  1. RootElement inmount()Finally, the function continues to call its own private function_rebuild()RootElement’s _child is constructed.
void _rebuild() {
    try {
      _child = updateChild(_child, widget.child, _rootChildSlot);
      assert(_child != null);
    } catch (exception, stack) {
      ...
      final Widget error = ErrorWidget.builder(details);
      _child = updateChild(null, error, _rootChildSlot);
    }
  }
Copy the code
  1. Here,updateChild()This function returns the result from a combination of the child and newWidget arguments as follows:
newWidget == null newWidget ! = null
child == null Return:null. Return new [Element]
child ! = null Remove child, Return:null return child or new [Element]

Since we are only talking about the first initialization here, the child == null passed in here, the newWidget is the widget that has been mounted to the rootWidget, So a newChild is initialized via the inflateWidget() function and returned to the rootElement. Note that newChild is not returned directly, but continues to call its mount() function via super.mount(). Note that ComponentElement and RenderObjectElement are not the same. RenderObjectElement initializes a RenderObject to mount to an Element. The whole process is to constantly find the widget’s child and construct the corresponding Element and renderObject.

Element updateChild(Element child, Widget newWidget, dynamic newSlot) { ... Element newChild; if (child ! = null) { ... } else { newChild = inflateWidget(newWidget, newSlot); }... return newChild; } @protected Element inflateWidget(Widget newWidget, dynamic newSlot) { ... final Element newChild = newWidget.createElement(); . newChild.mount(this, newSlot); . return newChild; }Copy the code

The end of the

Head buzzing… Due to the limited space of this article, this is the end. We will continue to talk about Flutter next time. If there are mistakes in Flutter, please correct them and learn and improve them together.