[Newbie] Chapter 1. Flutter overview
[Newbie] Chapter 2. Flutter getting started
[Newbie] Chapter 3. Flutter initial setup
Content
- Widget lifecycle
- State management approach
Widget’s lifecycle
Flutter has two types of widget: StatefulWidget vs StatelessWidget
- The widget has its own properties which passed via constructor
- The stateless widget doesn’t keep any state
- The stateful widget keeps a state object which contains all value of that state
What is the state’s lifecycle?
We have 2 approaches when implemented UI
- Approach 1: Implement all child widgets inside the root widget. In this case, we just use only one state stored at the root widget. Any changes from any child widget will impact on state and rebuild all children on the widget tree. The problem with this approach is when the widget tree grows too big, the set state needs to take much of the performance to render.
- Approach 2: Separate child widget by new StatefulWidget (not separated by function returned widget) In this case, the state will be separated also. If you change state from root it will impact all cascade child of course. But if you change state on child widget, it does not affect friends widgets. The problem with this approach is having a lot of states need to handle smoothly.
Some notes for the widget when using
- Ensure
WidgetsFlutterBinding
initialized by at this line to main function ofmain.dart
beforerunApp(MyApp());
WidgetsFlutterBinding.ensureInitialized();
- To make sure executing after widget built by
addPostFrameCallback
class AppContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
WidgetsBinding.instance.addPostFrameCallback((_) => onAfterBuild(context));
return …..;
}
// @nhancv 10/25/2019: After widget initialized.
void onAfterBuild(BuildContext context) {
// do anything here
}
}
AppLifecycleState
With Flutter, how to know the app go to the background or foreground via WidgetsBindingObserver
class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.paused) {
// Background
}
if (state == AppLifecycleState.resumed) {
// Foreground
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('AppLifecycleState'),
),
body: Center(),
);
}
}
To get more details of AppLifecycleState
:
https://api.flutter.dev/flutter/dart-ui/AppLifecycleState-class.html
State management approach

For more detail about some state management approaches:
- https://flutter.dev/docs/development/data-and-backend/state-mgmt
- https://medium.com/beesightsoft/flutter-state-management-2455c60cc423
I introduce to you a lib called bflutter
to help you handle state with Bloc approach.
For simple, just keep in mind:
- Anywhere can emit a signal
- Anywhere can catch a signal
- Emit and catch meet each other via stream
Therefore, with bflutter
you just define the logic from data input, config place which wants to take data for display or filter or something. When you want to trigger a logic, just push out a signal. That’s it.
Go to an example
Based on the initial project, I added an EmptyWidget
extend from StatelessWidget
, put print log in in build
function
Here is setState approach
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
print('build $_counter');
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
EmptyWidget(),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class EmptyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('build empty widget');
return Container();
}
}
I added a log in build function, run the app, click on ‘+’ to five and let’s see

Apply bflutter
- Install: https://pub.dev/packages/bflutter#-installing-tab-
- Modify your state object
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
final bloc = BlocDefault<int>();
void _incrementCounter() {
_counter++;
bloc.push(_counter);
}
@override
Widget build(BuildContext context) {
print('build $_counter');
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
EmptyWidget(),
Text(
'You have pushed the button this many times:',
),
StreamBuilder(
stream: bloc.stream,
initialData: 0,
builder: (context, snapshot) {
return Text(
'${snapshot.data}',
style: Theme.of(context).textTheme.display1,
);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
class EmptyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('build empty widget');
return Container();
}
}
- Run the app, press ‘+’ to increase counter to 5 and see the magic
- The app does not print build widget anymore and the counter keeps working fine. Yeah.