Mobile Development 18 min read

Mastering Flutter's StatefulWidget and App Lifecycle

This article explains the complete lifecycle of Android activities, iOS view controllers, and Flutter's StatefulWidget, shows how to place initialization and business logic, demonstrates key lifecycle methods with code examples, and covers Flutter app‑level lifecycle states for robust mobile development.

BaiPing Technology
BaiPing Technology
BaiPing Technology
Mastering Flutter's StatefulWidget and App Lifecycle

Android

If you are an Android developer, the Activity lifecycle is familiar:

onCreate

onStart

onResume

onPause

onStop

onDestroy

iOS

If you are an iOS developer, the UIViewController lifecycle is well known:

viewDidLoad

viewWillAppear

viewDidAppear

viewWillDisappear

viewDidDisappear

viewDidUnload

Flutter

Flutter has two main widget types: StatelessWidget (immutable) and StatefulWidget (mutable). This article focuses on the lifecycle of StatefulWidget .

StatelessWidget

Stateless widgets are immutable; they render once and only rebuild when the parent changes configuration, when the widget is first inserted, or when an inherited widget changes.

StatefulWidget

A StatefulWidget consists of two classes: the immutable widget class and a mutable State class created by createState(). The State holds the mutable data and persists throughout the widget’s lifetime.

StatefulWidget Lifecycle

createState : Called when the widget is created; sets mounted to true.

initState : Runs once for one‑time initialization (e.g., variable setup, subscriptions, server calls).

didChangeDependencies : Invoked when the widget’s dependencies (e.g., inherited widgets, locale, theme) change; marks the widget dirty and triggers build.

build : Returns the widget tree; may be called many times, so it should contain only UI construction logic.

reassemble : Called only in debug mode during hot‑reload.

didUpdateWidget : Called when the parent rebuilds with a new widget instance; followed by another build.

deactivate : Called when the widget is removed from the tree but might be reinserted elsewhere.

dispose : Called when the widget is permanently removed; releases resources and sets mounted to false.

Important Concepts (Not Lifecycle Methods)

mounted : Indicates whether the State is currently attached to the widget tree.

dirty : The State needs rebuilding on the next frame.

clean : The State is up‑to‑date and will not rebuild.

Four Main Phases

Initialization: createState and initState.

Creation: didChangeDependencies and build.

Update: Multiple build calls triggered by didChangeDependencies, setState, or didUpdateWidget.

Destruction: deactivate and dispose.

Component First‑Load Process

The following code demonstrates a simple counter widget and logs each lifecycle method to verify the order.

import 'package:flutter/material.dart';

class CountWidget extends StatefulWidget {
  CountWidget({Key key}) : super(key: key);

  @override
  _CountWidgetState createState() {
    print('count createState');
    return _CountWidgetState();
  }
}

class _CountWidgetState extends State<CountWidget> {
  int _count = 0;
  void _incrementCounter() {
    setState(() {
      print('count setState');
      _count++;
    });
  }

  @override
  void initState() {
    print('count initState');
    super.initState();
  }

  @override
  void didChangeDependencies() {
    print('count didChangeDependencies');
    super.didChangeDependencies();
  }

  @override
  void didUpdateWidget(CountWidget oldWidget) {
    print('count didUpdateWidget');
    super.didUpdateWidget(oldWidget);
  }

  @override
  void deactivate() {
    print('count deactivate');
    super.deactivate();
  }

  @override
  void dispose() {
    print('count dispose');
    super.dispose();
  }

  @override
  void reassemble() {
    print('count reassemble');
    super.reassemble();
  }

  @override
  Widget build(BuildContext context) {
    print('count build');
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text('$_count', style: Theme.of(context).textTheme.headline4),
          Padding(
            padding: EdgeInsets.only(top: 100),
            child: IconButton(
              icon: Icon(Icons.add, size: 30),
              onPressed: _incrementCounter,
            ),
          ),
        ],
      ),
    );
  }
}

In main.dart we load the widget:

import 'package:flutter/material.dart';
import './pages/count_widget.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
      body: CountWidget(),
    );
  }
}

Running the app prints the first four lifecycle calls:

flutter: count createState
flutter: count initState
flutter: count didChangeDependencies
flutter: count build

Pressing the + button triggers setState and build:

flutter: count setState
flutter: count build

Hot‑reload (⌘ S) invokes reassemble, didUpdateWidget, and build:

flutter: count reassemble
flutter: count didUpdateWidget
flutter: count build

Removing the widget (commenting it out) triggers reassemble, deactivate, and dispose:

flutter: count reassemble
flutter: count deactivate
flutter: count dispose

When Does a Widget Re‑build?

Three situations cause a rebuild: setState: Direct state change within the widget. didChangeDependencies: A dependent global state (e.g., locale, theme) changes. didUpdateWidget: The parent rebuilds with a new widget instance.

Component Destruction

When a parent removes a child, the child’s deactivate runs first, followed by its dispose. Finally, the parent’s deactivate and dispose execute.

Flutter App Lifecycle

Beyond widget lifecycles, Flutter apps have lifecycle callbacks via WidgetsBindingObserver. The following example logs app‑level state changes:

import 'package:flutter/material.dart';

class AppLifecycle extends StatefulWidget {
  AppLifecycle({Key key}) : super(key: key);

  @override
  _AppLifecycleState createState() {
    print('sub createState');
    return _AppLifecycleState();
  }
}

class _AppLifecycleState extends State<AppLifecycle> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    print('sub initState');
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    print('didChangeAppLifecycleState');
    if (state == AppLifecycleState.resumed) {
      print('resumed');
    } else if (state == AppLifecycleState.inactive) {
      print('inactive');
    } else if (state == AppLifecycleState.paused) {
      print('paused');
    } else if (state == AppLifecycleState.detached) {
      print('detached');
    }
  }

  @override
  Widget build(BuildContext context) {
    print('sub build');
    return Container(child: Text('data'));
  }
}

The four AppLifecycleState values are:

resumed : App is visible and responding to user input (foreground).

inactive : App is in a non‑interactive state (e.g., during a phone call or when a system dialog appears).

paused : App is not visible and does not receive input (background).

detached : App is still attached to the Flutter engine but has no host view.

Other observer callbacks such as didChangeAccessibilityFeatures, didHaveMemoryPressure, didChangeLocales, and didChangeTextScaleFactor can also be overridden for special cases.

Conclusion

This article covered the lifecycle of Android activities, iOS view controllers, and especially Flutter's StatefulWidget , as well as app‑level lifecycle events. Understanding these stages helps you place initialization, business logic, and cleanup code correctly, leading to more stable and maintainable Flutter applications.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DARTFlutterLifecycleApp LifecycleStatefulWidget
BaiPing Technology
Written by

BaiPing Technology

Official account of the BaiPing app technology team. Dedicated to enhancing human productivity through technology. | DRINK FOR FUN!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.