Flutter Lifecycle for Android and iOS Developers

Mariano Zorrilla
Flutter Community
Published in
5 min readJun 24, 2019

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?

I have the answer for all those questions in this post! 🤓 📖

Android

If you’re coming from the green robot development, the Activity lifecycle is something we had to remember so many times for every job interview:

  • onCreate.
  • onStart
  • onResume

— — — — — — — —

  • onPause
  • onStop
  • (forever alone onRestart)
  • onDestroy

Most of our login ended up inside the onCreate method: Init Views, Database, Listeners, etc. Lifecycles like onResume and onPause have a great use to know if the user is leaving the screen o coming back to.

iOS

If you’re #TeamApple this logic sounds so familiar and you already know the lifecycle of a UIViewController:

  • viewDidLoad
  • viewWillAppear
  • viewDidAppear

— — — — — — — — —

  • viewWillDisappear
  • viewDidDisappear
  • viewDidUnload

As you can see, both platform use the same (almost) amount of steps to create and destroy a screen. viewDidLoad() will hold a lot of our business logic and the Will/Did Appear/Disappear ones are great to save information, know when the user is leaving the screen, etc

Flutter ❤️

But what about us? Does a Widget follow this logic? If we go back to our first set of questions, onCreate and viewDidLoad got already answered on each mobile OS, now we need to know the equivalent for Flutter.

If you’ve been around Flutter, you’ll notice 2 major Widgets: StatelessWidget and StatefulWidget. In order to make this post valid 😋 we’ll focus over StatefulWidget as that one holds a similar logic like Android and iOS.

StatefulWidget

This is one of the most important Widgets because it holds a State Widget, this one know when something changed and re-draws anything necessary over our screen. The lifecycle of this one is the following:

  • createState
  • initState
  • didChangeDependencies
  • build
  • (didUpdateWidget)

— — — — — — — — — — —

  • deactivate
  • dispose

You’ll notice a lot more “states” for the creating than the destruction, this is due to the construction and re construction of the Widgets and their State.

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();
}

initState()

You’ll need to write this one and will also notice how useful it is. Is the first method called after the Widget is created. This is our equivalent to onCreate() and viewDidLoad(). Over this Lifecycle we can also check some aspects of the Widget like: was it render? is it currently mounted?

mounted

All widgets have this values and turn into true when the buildContext is assigned and is currently on a tree. It’ll keep that values until dispose gets called.

addPostFrameCallback

This one needs to be called inside your initState() by doing the following:

import 'package:flutter/scheduler.dart';@override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) => {});
}

This is a callback for the end of the frame, it only gets called once and we know for sure that the Widget build is completed.

didChangeDependencies()

This method is called immediately after initState() on the first time the widget is built. If your StatefulWidgets depends from a InheritedWidget it will call again if a change is necessary.

build()

We can say for sure this method is the most “important” one. Here it relays your entire tree of Widgets to be render and is called right after didChangeDependencies(). All the GUI is render 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.

deactivate()

Again, like didUpdateWidget, this one is not a common one to see. We’re getting to the point were our Widget start “dying”.

The framework calls this method whenever it removes this State object from the tree. In some cases, the framework will reinsert the State object into another part of the tree.

dispose()

This one is very important and is called when this object and its State is removed from the tree permanently and will never build again.

This Lifecycle is the one you need to unsubscribe streams, dispose animations, etc. Is the equivalent opposite of initState.

WidgetsBindingObserver

What if we need to know when our App when to background? and when it comes to foreground? Is there any way to detect that? Well… is your lucky day as I’m going to explain to you right now.

We need to make a small change inside our StatefulWidget and to our State class in particular:

class _MyScreenState extends State<MyScreen> with WidgetsBindingObserver

Once we implement the abstract class WidgetsBindingObserver we need to “observe” the changes of our App Lifecycle State. To do so, we need to add the following inside our initState:

WidgetsBinding.instance.addObserver(this);

and this line inside our dispose:

WidgetsBinding.instance.removeObserver(this);

Great! But where you I “hear” those changes? didChangeAppLifecycleState will be:

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.paused) {
// went to Background
}
if (state == AppLifecycleState.resumed) {
// came back to Foreground
}
}

This trick is sooooo useful! If you app needs to show a notification when goes to background, if you need to save data in that moment, if you need to show a popup when the user is back, etc there’s so many uses cases for this logic!

I really hope this information is useful for a lot of Android and iOS developers moving into Flutter. The first steps into this amazing framework may feel confusing at first, but having this life hacks, will make your life easier 🎉🎉🎉

Oh! I almost forgot! “Why is the sky blue?”

Blue light is scattered in all directions by the tiny molecules of air in Earth’s atmosphere. Blue is scattered more than other colors because it travels as shorter, smaller waves. This is why we see a blue sky most of the time.

Or maybe because it was inspired by the Flutter logo colors 😋

--

--

Mariano Zorrilla
Flutter Community

GDE Flutter — Tech Lead — Engineer Manager | Flutter | Android @ Venmo