Lifecycle of Widgets

One of the most confusing ideas transitioning from Android and/or iOS is to understand how Flutter handles its lifecycle.

Where’s my onCreate()? viewDidLoad()? How do I know where to put my business logic? Why I only have a build method? Why is the sky blue?

The lifecycle of this one is the following:

createState()

When we build a new StatefulWidget, this one calls createState() right away and this override method MUST exist:

class MyScreen extends StatefulWidget {
  @override
  _MyScreenState createState() => _MyScreenState();
}

This method is responsible for creating state object.

mounted(true/false)

Once we create a State object, the framework mounted the State object by associating it with a BuildContext before calling initState() method. All widgets have a bool mounted property. It is turned true when the buildContext is assigned.

initState()

This is the first method called when a stateful widget is created after the class constructor. The initState() is called only once. It must called super.initState(). Here, you can initialize data, properties and subscribe to Streams or any other object that could change the data on this widget.

You’ll need to write this one and will also notice how useful it is. This is the first method called after the Widget is created.

@override
initState() {
  super.initState();
  // Add listeners to this class
  cartItemStream.listen((data) {
    _updateWidget(data);
  });
}

didChangeDependencies()

This method is called immediately after initState() method on the first time the widget is built

It will also be called whenever an object that this widget depends on data from is called. For example, if it relies on an InheritedWidget, which updates. The build() method is always called after didChangeDependencies is called, so this is rarely needed.

build()

It shows the part of the user interface represented by the widget. The framework calls this method in several different situations

All the GUI is rendered here and will be called every single time the UI needs to be render because drawing again is a cheap operation.

didUpdateWidget()

Maybe this is not a Lifecycle you’ll came across very often but, like the name saids, it’ll be called once the parent Widget did a change and needs to redraw the UI. You’ll get the oldWidget parameter and you can compare it with the current widget to do some extra logic right there.

This method is basically the replacement for 'initState()' if it is expected the Widget associated with the widgets's state needs to to be rebuilt!

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

@override
void didUpdateWidget(Widget oldWidget) {
  if (oldWidget.importantProperty != widget.importantProperty) {
    _init();
  }
}

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 this build context should be rebuilt.

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

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

deactivate()

This is called when State is removed from the widgets tree, but it might be reinserted before the current frame change is finished. This method exists because State objects can be moved from one point in a tree to another.

dispose()

'dispose()' is called when the State object is removed, which is permanent. Here you can unsubscribe and cancel all animations, streams, etc.

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