Stateful Widget Lifecycle

When a Flutter builds aStatefulWidget, itcreates a State object. Thisobject is where all themutable state for that widget is held.

The concept of state is defined by two things:

  • The data used by the widget might change.

  • The data can't be read synchronously when the widget is built. (All statemust be established by the time the build method is called).

The lifecycle has the following simplified steps:

Why Are StatefulWidget and State Separate Classes?

In one word: performance.

The tldr version is that State objects are long lived, but StatefulWidgets(and all Widget subclasses) are thrown away and rebuilt whenever configurationchanges. It's very inexpensive ie cheap for Flutter to rebuild a mutable widget.

As State isn't blown away on every rebuild, it avoidsexpensive computations, and gets at the states property, getters, setters etc everytimesomething is rebuilt frame by frame.

Important is that this is what allows Flutter animations to exist. As State isn'tthrown away, it can constantly be rebuilding it's Widget in response to datachanges, and when required, if any.

1. createState()

When Flutter is instructed to build aStatefulWidget, itimmediately callscreateState(). Thismethod must exist. A StatefulWidget rarely needs to be more complicated than this.

  1. class MyHomePage extends StatefulWidget {
  2. @override
  3. _MyHomePageState createState() => new _MyHomePageState();
  4. }

2. mounted is true

When createStatecreates the state class, a buildContext is assigned tothat state.

A BuildContext is, overlysimplified, the place in the widget tree in whichthis widget is placed. Here's a longer explanation.

All widgets have a bool this.mounted property. It is turns true when thebuildContext is assigned. It is an error to call setState when a widget isunmounted.

tip: This property is useful when a method on your state calls setState()but it isn't clear when or how often that method will be called. Perhaps itsbeing called in response to a stream updating. You can use if (mounted) {…to make sure the State exists before calling setState().

3. initState()

This is the first method called when the widget is created (after the classconstructor, of course.)

initState iscalled once and only once. It must also call super.initState().

This @override method is the best time to:

  • Initialize data that relies on the specific BuildContext for the createdinstance of the widget.
  • Initialize properties that rely on this widgets 'parent' in the tree.
  • Subscribe to Streams, ChangeNotifiers, or any other object that could changethe data on this widget.
  1. @override
  2. initState() {
  3. super.initState();
  4. // Add listeners to this class
  5. cartItemStream.listen((data) {
  6. _updateWidget(data);
  7. });
  8. }

4. didChangeDependencies()

The didChangeDependenciesmethod is called immediately after initState on the first time thewidget is built.

It will also be called whenever an object that this widget depends on datafrom is called. For example, if it relies on an InheritedWidget, which updates.

build is always called after didChangeDependencies is called, so thisis rarely needed. However, this method is the first change you have to callBuildContext.inheritFromWidgetOfExactType. This essentially would make thisState 'listen' to changes on a Widget it's inheriting data from.

The docs also suggest that it could be useful if you need to do network calls(or any other expensive action) when an InheritedWidget updates.

5. build()

This method is called often (think fps + render). It is a required, @override andmust return a Widget.

Remember that in Flutter all gui is a widget with a child or children, even'Padding','Center'.

6. didUpdateWidget(Widget oldWidget)

didUpdateWidget() is calledif the parent widget changes and has to rebuild this widget (because it needsto give it different data), but it's being rebuilt with the same runtimeType,then this method is called.

This is because Flutter is re-using the state, which is long lived. In thiscase, required is to initialize some data again, as one would in initState().

If the state's build() method relies on a Stream or other object that canchange, unsubscribe from the old object and re-subscribe to the new instance indidUpdateWidget().

tip: This method is basically the replacement for 'initState()' if it is expectedthe Widget associated with the widgets's state nrrds to to be rebuilt!

Flutter always called build() after this, so any subsequent further calls to setState isredundant.

  1. @override
  2. void didUpdateWidget(Widget oldWidget) {
  3. if (oldWidget.importantProperty != widget.importantProperty) {
  4. _init();
  5. }
  6. }

7. setState()

The 'setState()'method is called often from the Flutter framework itself and from the developer.

It is used to notify the framework that "data has changed", and the widget at thisbuild context should be rebuilt.

setState() takes a callback which cannot be async. It is for this reasonit can be called often as required, because repainting is cheap :-)

  1. void updateProfile(String name) {
  2. setState(() => this.name = name);
  3. }

8. deactivate()

This is rarely used.

'deactivate()' iscalled when State is removed from the tree, but it might bereinserted before the current frame change is finished. This method existsbasically because State objects can be moved from one point in a tree toanother.

9. dispose()

'dispose()' is calledwhen the State object is removed, which is permanent.

This method is where to unsubscribe and cancel all animations, streams,etc.

10. mounted is false

The state object can never remount, and an error is thrown is setState() iscalled.