StatefulWidget’s Key & State

An in-depth look at Flutter’s StatefulWidget and its Lifecycle.

You’re going to use StatefulWidget’s. If you're going to use Flutter, you’re going to use StatefulWidget’s. A lot of them. Together. One on top of the other. It’s inevitable. As you learn Flutter more and more, your apps will get more complicated…with more Widgets. More StatefulWidgets. A Stateless widget never changes. A Stateful widget can change in response to user interactions or other events. This widget’s ‘state’ is represented by a separate class object called, well… State. The State object consists of values that can change. The State object contains its associated widget’s ‘mutable state.’ — it stores values that can change over time. When those values have changed, more often than not, the associated StatefulWidget is re-created.

Learn By Example

I Like Screenshots. Click For Gists.

No Moving Pictures No Social Media

Let’s begin.

Other Stories by Greg Perry

Build The Screen

Set To Rebuild

Count Your Builds

Let’s take a closer look at this. There’s a number of print() functions now introduced to the code. To emphasize when each class is instantiated (i.e. when each widget is created), I’ve explicitly defined the constructor for both the StatefulWidget object and the State object — supplying a print() function in each. There are print commands placed in other locations of interest to demonstrate the ‘lifecycle’ of the StatefulWidget and its State object. Click on the screenshot below to get your own copy. You can then follow along.

counter_app.dart

What Happens On Startup

Press The Button. See What Happens.

You pretty much get the idea. Every time you press the button, you’re going to see the State object’s build() function get called again — displaying the value in the State object’s instance variable, _counter. Below, is a screenshot of the console screen when the button was pressed six times. Pretty simple.

Initialize The State

With such a simple example to work with, I nevertheless wish to convey some of the common practices found in more complex applications — one being the supplying of default values to such instance variables in the initState() function. This function is called only when a State object is first created, and so the app will behave just as before. Note, a print command will be placed inside the initState() function as well.

counter_app.dart

It all behaves the same. However, now you see an additional line in the console screen. Again, you will see this line only once when the State object is first instantiated.

It’s Going To Get Complicated

Two Screens; Three Counters

Original version vs Latest version

Below are now screenshots of this more complicated counter app. Tap or click on the screenshots to get a copy for yourself. You can see the original State object, _MyHomePageState, now has its own counter?! Additionally, a new StatefulWidget called, _FirstPage, now displays the original screen!

Further on in the code, you will find the ‘Second Page’ StatefulWidget that will display a separate counter on a separate screen. Again, it’s peppered with print commands so we can follow the ‘sequence of events’ for such widgets.

And so, looking at the console screen, you can see the print commands highlight the sequence in which the widget and State objects are created and the sequence in which their functions are called. For example, when the home screen is first displayed, you can see the State objects involved first call their initState() functions before finally calling their build() functions. When it comes to the home screen, it’s the State object, _FirstPageState, with widgets in its build() function that displays the first screen or first page.

Follow the ‘arrow lines’ on after the other, and you can see the logic involved when displaying the first screen. Each StatelessWidget and StatefulWidget are created one after the other. And with each StatefulWidget, you can see its corresponding State object is created and their functions called.

To The Second

Please, ignore the first paragraph. It now no longer occurs.

But Don’t Forget The First

In Flutter, Widget’s are being re-created all the time. Constantly. Every time you cause a build() function to run, you’re re-creating the Widgets found therein. Get used to that fact, but did you notice what didn’t get called in that sequence of events? That’s right! You didn’t see ‘the first’ State object get re-created and or it’s initState() function get called again! I’ve put them where they would have gone in the sequence below, but, in fact, they’re not called. The State object, _FirstPageState, was left alone only to run its build() function again. So why weren’t they called?

No constructor call or initState() call

By the way, the first State object calls its build() function and yet is not displayed due to Flutter’s routing mechanism. We’re on a separate overlay on the stack of routes by this time and so are presented with the ‘Second Page’ StatefulWidget and the contents of it’s State object’s build() function instead.

‘Second Page’ Button calls a Navigator

The State Remains

Title Count

Remember, in this app, when you click on a button a setState() function will be called. That means a build() function will be called soon after. Keep that in mind as we continue.

Build Your Home

And so, back up to the State object, _MyHomePageSate, its build() function is soon called so to convey the new ‘counter’ value in the app’s title. See the red arrow below.

The Console Knows

Wait A Second!

Looks pretty straightforward, right? With every push of the button, the State object, _SecondPageState, has it’s setState() and build() functions called in turn.

Back To First

The First One Goes

Pop Goes The State

And so, if you return to the Second Page, you’ll find the count set back to zero. The StatefulWidget and its accompanying State object have both been created again when you return to the Second Page through the Navigator class.

Count On Home

The Key State

Now, why would you want ‘to clear’ the State object of a screen? Because, and I can say this from experience, you may want to reset the ‘mutable values’ in a State object for one reason or another — and Flutter easily allows for this.

When you press the ‘New Key’ button, you can see below in the code that what happens is that a private variable is assigned a new unique Key value. Doing so has the effect we’re looking for. Returning to the first screen, the counter is returned to zero. That’s because the State object has been re-created.

That variable is a high-level variable — defined within the dart file and not in any particular class. Now there’s no special reason to do this. In fact, it could have just as easily been defined as an instance variable in the State object, _MyHomePageState. Regardless, note it’s defined in the file at compile-time and then assigned to the StatefulWidget, _FirstPage. Below, you can see the sequence that occurs after the ‘New Key’ button is pressed.

You can see in the screenshot above when you click on the ‘New Key’ button, the first screen’s StatefulWidget, FirstPage, gets re-created as usual. However, something’s changed. It’s State object _FirstPageState is re-created as well. Now the sequence highlighted with red arrows is a little confusing, but we’ll walk through it. Starting with the first red arrow, we see the ‘original instance’ of the State object calling its deactivate() function. The next three arrows depict the ‘new instance’ of the State object being created and calling its build() function. The last arrow points back to the ‘original instance’ of the State object as it calls its dispose() function and prepares itself to be recycled.

Note, that dispose() function could appear any time after the deactivate() function call — right after or much much later. That’s why people suggest you clear up ‘time constraint’ resources in the deactivate() function as it’s consistently and predictably called when the State object’s replaced by a new instance.

And so, when the ‘First Page’ button is pressed to return to the first screen, we know the first screen’s StatefulWidget is always re-created. However, this time, it’s assigned a new ‘unique key.’ Doing so has the framework dispose the original State object so as to create a new one. So there you go. Besides testing widgets, there’s another reason to assign keys to widgets. The Flutter team, of course, has a video on when to use Keys and would likely supply more insight.

When to Use Keys

Get A Lifecycle

That’s enough for now. Some stuff to keep in mind when working with your many StatefulWidgets — and their States.

Cheers.

Video on YouTube

→ Other Stories by Greg Perry

DECODE Flutter on YouTube

Freelance Developer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store