Introduction

The foundation of Flutter is widget. According to whether it needs to interact with users, widgets can be divided into StatelessWidget and StatefulWidget. StatelessWidget can only simply initialize the widget according to the incoming state. If you want to realize the complex function of interacting with the user, you need to use StatefulWidget.

But for StatefulWidget itself, it does not store any state, all states are stored in the State associated with StatefulWidget.

Today, let's explore the relationship between StatefulWidget and State.

StatefuWidget and State

The definition of StatefulWidget is very simple, it is an abstract class, inheriting it only needs to implement a createState method:

 abstract class StatefulWidget extends Widget {
 
  const StatefulWidget({ Key? key }) : super(key: key);

  @override
  StatefulElement createElement() => StatefulElement(this);

  @protected
  @factory
  State createState(); 
}

Note that createState here is a factory class method. This means that a StatefulWidget can create multiple States.

For example, if you remove a StatefulWidget from the tree and insert it into the tree again later, Flutter will call StatefulWidget.createState again to create a new State object.

So is the StatefulWidget that created it accessible in State? The answer is yes.

A widget of type T is defined in State, which is a subclass of StatefulWidget:

 abstract class State<T extends StatefulWidget> with Diagnosticable {
  T get widget => _widget!;
  T? _widget;

The _widget here does not need to be set by us. This _widget is set by the flutter framework before calling initState. The _widget is actually the StatefulWidget associated with the State.

We can use the widget directly in the State to reference it.

State life cycle

After talking about the relationship between StatefulWidget and State, let's take a look at how State changes. In layman's terms, what is the life cycle of State.

Generally speaking, the life cycle of a State has 4 states, namely created, initialized, ready and defunct states. These four states are defined in the enumeration class _StateLifecycle:

 enum _StateLifecycle {
  /// State已经被创建成功了,State.initState方法被调用。
  created,

  /// State.initState方法虽然被调用了,但是State对象还没有构建完毕。 这时候会调用State.didChangeDependencies方法.
  initialized,

  /// State对象创建成功,State.dispose方法还没有被调用。
  /// called.
  ready,

  /// State.dispose方法被调用过了,State对象不允许再调用build方法。
  defunct,
}

Let's explain the life cycle of State in detail.

First, in order to create a State object, flutter calls the StatefulWidget.createState method. Because the StatefulWidget.createState method simply new a State object, the State object is in the created state at this time.

This newly created State object will be associated with a BuildContext. Note that this association is permanent and will not change.

Although the relationship does not change, the BuildContext itself can be moved in the tree. At this time, the State is in the mounted state.

Next, flutter will call the initState method in State.

For the specific implementation of State, the initState method needs to be rewritten to initialize the state of the State according to the BuildContext and Widget associated with the State. Among them, BuildContext and Widget can be accessed by using the context and widget properties of State.

Then the flutter framework will call the didChangeDependencies method of the state.

When will this method be called? According to flutter, it is called when the object that State depends on changes.

For example, if an InheritedWidget object is referenced in the State's build method, and the InheritedWidget object changes later. At this time, flutter will call the didChangeDependencies method.

Let's look at the definition of this method in State:

 void didChangeDependencies() { }

It can be seen that this method itself is an empty method body, because it is not an abstract method, so subclasses do not need to enforce it.

Why don't sub-objects of State generally need to override this method? This is because if flutter detects a change in dependencies, it will call the build method of State. Usually, we don't need to refactor so often.

Of course, there will also be some special cases, such as real-time network communication with high real-time requirements.

At this point, the State object is completely initialized, and then the build method can be called an unlimited number of times to reconstruct the user interface.

State can also actively call the setState method to reconstruct the subtree.

In addition to State actively calling the setState method, there are some external changes that will lead to changes in State, such as:

 void didUpdateWidget(covariant T oldWidget) { }

When will this method be called?

We know that Widgets will not change. Each Widget has a unique key to mark it, but the parent Widget can use the same key and runtimeType to modify the current widget. Because the Widget is unchanged, a new widget is generated. At this time, flutter will call the didUpdateWidget method in State and pass in the old Widget as a parameter.

Note that the flutter framework will automatically call the build method after calling didUpdateWidget, so in the process of writing the program, be careful not to call it repeatedly.

If it is in the development process, flutter also supports hot reloading. At this time, the reassemble method of the state will be called:

 void reassemble() { }

The flutter framework will call the build method after triggering the hot reload, so in general, we don't need to override the reassemble method.

We just mentioned that the parent Widget may modify the configuration file of the current Widget. If the key of the current Widget is modified, the old widget will be in a deactivate state, and the deactivate method in the widget will be called:

 void deactivate() {
    super.deactivate();
    assert(
      !renderObject.attached,
      'A RenderObject was still attached when attempting to deactivate its '
      'RenderObjectElement: $renderObject',
    );
  }

We can override this method to handle some resource cleanup.

Note that the widget is now deactivated, but that doesn't mean it's useless. Because flutter can also reinsert this widget into the object tree and continue to use it. Reinsert is achieved by calling the build method of the State object.

This operation is possible as long as the operation is performed before the end of an animation frame. The advantage of this is that state can also retain some resources and not release them, thereby improving efficiency.

Finally, if State does not need to be used, the dispose method of State will be called:

 void dispose() {
    assert(_debugLifecycleState == _StateLifecycle.ready);
    assert(() {
      _debugLifecycleState = _StateLifecycle.defunct;
      return true;
    }());
  }

When the State's dispose method is called, the State is in the unmounted state. At this time, the setState method of State can no longer be called, which means that the life cycle of State is over.

Summarize

The above is an introduction to the life cycle of State and State.

For more information, please refer to http://www.flydean.com/03-flutter-state/

The most popular interpretation, the most profound dry goods, the most concise tutorials, and many tricks you don't know are waiting for you to discover!

Welcome to pay attention to my official account: "Program those things", understand technology, understand you better!


flydean
890 声望432 粉丝

欢迎访问我的个人网站:www.flydean.com