In the last article we looked at the difference between a StatelessWidget and a StatefulWidget, which holds State and can Build itself. In this article, we will study the life cycle of State.

createState

In this article we have analyzed that the process of inserting the Element corresponding to the Widget into the Element Tree is implemented in the inflateWidget method:

Element inflateWidget(Widget newWidget, dynamic newSlot) {
    final Key? key = newWidget.key;
    final Element newChild = newWidget.createElement();
    newChild.mount(this, newSlot);
    return newChild;
  }
Copy the code

CreateElement () is a StatefulElement object created:

<! -- StatefulWidget --> StatefulElement createElement() => StatefulElement(this);Copy the code

Let’s look at the logic of StatefulElement(this) :

<! -- StatefulElement --> StatefulElement(StatefulWidget widget) : state = widget.createState(), super(widget) { state._element = this; state._widget = widget; } final State<StatefulWidget> state;Copy the code
  1. Call thewidget.createState()Method generates oneStateObject,StatefulElementObject holds thisstate;
  2. stateHold againStatefulElementObjects, that is, they existA circular referenceRelationship.
  3. State also holds the StatefulWidget object.

The reference logic of the three is somewhat convoluted, which can be expressed in a graph as follows:

We see that the StatefulElement does not need to refer directly to the StatefulWidget because it holds State, and thus holds the StatefulWidget indirectly.

StatelessElement needs to hold the StatelessWidget directly.

mounted

<! -- State --> bool get mounted => _element ! = null;Copy the code

Mounted becomes true when _element is assigned.

initState

Attaching the inflateWidget method above, the newly created Element object calls the mount method.

Because StatefulElement does not override the mount method, the parent ComponentElement’s mount method is actually called.

<! -- ComponentElement --> void mount(Element? parent, dynamic newSlot) { super.mount(parent, newSlot); _firstBuild(); }Copy the code

StatefulElement’s _firstBuild method calls state.initState()

<! -- StatefulElement --> void _firstBuild() { try { // 1 final dynamic debugCheckForReturnedFuture = state.initState() as dynamic; } finally { } state.didChangeDependencies(); super._firstBuild(); }Copy the code

didChangeDependencies

From the above code, we can see that the didChangeDependencies method is called in _firstBuild, that is, the initState and didChangeDependencies methods are executed together in _firstBuild.

When we see performRebuild, state also calls the didChangeDependencies method when StatefulElement’s _didChangeDependencies becomes true.

<! -- StatefulElement --> void performRebuild() { if (_didChangeDependencies) { state.didChangeDependencies(); _didChangeDependencies = false; } super.performRebuild(); }Copy the code

When the value of the InheritedWidget changes, it is possible to change the value of _didChangeDependencies to true.

build

Let’s look at the super.performrebuild () method:

<! -- ComponentElement --> void performRebuild() { Widget? built; try { built = build(); }finally { } _child = updateChild(_child, built, slot); } <! -- StatefulElement --> Widget build() => state.build(this);Copy the code

The build method is called in the performRebuild method of StatefulElement, so state calls the build method.

didUpdateWidget

void update(StatefulWidget newWidget) { super.update(newWidget); final StatefulWidget oldWidget = state._widget! ; _dirty = true; state._widget = widget as StatefulWidget; try { final dynamic debugCheckForReturnedFuture = state.didUpdateWidget(oldWidget) as dynamic; } finally { } rebuild(); }Copy the code

When Element calls update, state calls the didUpdateWidget method. When the parent Widget causes a rebuild Build, the Update method is called if element can be reused.

setState

Mounted: true This method is called by the developer, and as long as mounted is true, Self rebuild can be implemented.

deactivate

The state deactivate method is called when an element changes from active to inactive.

void deactivate() {
    state.deactivate();
    super.deactivate();
}
Copy the code

At this point, element is removed from the Element Tree, but may be added back to the Tree if it can be reused.

dispose

State’s Dispose method is called when an Element changes from inactive to defunct.

void unmount() {
    super.unmount();
    state.dispose();
    state._element = null;
}
Copy the code

mounted == false

State. _element = null; Mounted becomes false. State will be collected by the garbage collector.

conclusion

  1. inStatefulWidgetinstantiationStatefulElementObjectwidget.createState()createStateObject, and thenStateandStatefulElementMutual reference;
  2. StateWith theStatefulElementAfter quoting,mountedbecomestrue, can be calledsetStateMethods;
  3. StatefulElementObject and then callmountMethod to mount toElement TreeGo up. Called after mountinginitStateanddidChangeDependenciesMethods;
  4. thenelementWill be calledperformRebuildMethod is calledStatethebuildMethod, ifInheritedWidgetChanges in the value ofdidChangeDependenciesMethods;
  5. The parent WidgetCause the refactoringBuildWhen, ifelementIt will be called if it can be reusedStatethedidUpdateWidgetMethods;
  6. whenelementfromactiveintoinactive“Will be calledstatethedeactivateMethods;
  7. whenelementfrominactiveintodefunctIs calledstatethedisposeMethod, and sets _element to null, and cannot be called againsetStateMethods;
  8. Wait for the garbage collector to collect.