Flutter Performance Checks — Part 1

Dave Parth
Globant
Published in
5 min readJan 13, 2020

Flutter, a solid cross-platform available in the market. Many of us are developing apps in flutter but do not know why they asked us to do something, we will clear that topics.

Do not put everything in the build function.
This is recommended by flutter devs to not put everything in one widget build method. but why?
Let’s have a look.

Create a Flutter app using “Flutter create app_name” and you will get something like the counter-example.

If we check in the Flutter Performance tab in the Android Studio (will get into the observatory afterward — Observatory is Dart tool for profiling). Now every time we tap to increment the counter it gets updated and so is the MyHomePage, Scaffold, Appbar, FloatingActionButton and a Text widget. Which is probably not we are updating so why it’s building every time?

Well the problem lies in that setState method

void _incrementCounter(){
setState(() {
_counter++;
});
}

When we call setState we are notifying stateful widget that data has been changed and it needs to rebuild the tree. Due to that, we have all the widgets in the one single build method like this:

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
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),
),
);
}

and it builds every widget out there.

The solution might be to separate the changing elements and build a new separate class.

Let’s change code a little bit what will be wrong inside this approach.

class HomePageContainer extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Title of the page"),
),
body: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() async{
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme
.of(context)
.textTheme
.display1,
),
RaisedButton(
onPressed: _incrementCounter,
child: Text("Increment"),
)
],
),
);
}
}

We have created one Container class which will have an appbar and scaffold and a child widget which is our changing widget. For now, it looks good.

The scaffold and appbar no longer build more than one time, so it’s a good sign but why three texts and a raised button build 6times in a row? Let’s go another level there might be the case that you will experience this thing:

class _MyHomePageState extends State<MyHomePage> {
...
@override
Widget build(BuildContext context) {
return Center(
child: Column(
...
children: <Widget>[
MessageContainer(),
Text(
'$_counter',
...
),
RaisedButton(
...
)
],
),
);
}
}
class MessageContainer extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Text(
'You have pushed the button this many times:',
);
}
}

In another case, you will be having something like this where one stateful widget contains another stateful or stateless widget.

Let’s think before we execute this code, what will happen if we click the raised button will MessageContainer need to rebuild? I mean there isn’t any change and we don’t want to as we separated it in another class right?

Well, the answer is no, It’s going to be rebuilt every time. we click the raised button as in the build method we are calling MessageContainer() which is not at all a constant.

so now our best option is to make it a constant for every widget we don’t want to be updated.

class _MyHomePageState extends State<MyHomePage> {
...
Widget _raisedButton;get raisedButton {
if(_raisedButton == null)
_raisedButton = RaisedButton(
onPressed: _incrementCounter,
child: const Text("Increment"),
);
return _raisedButton;
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const MessageContainer(),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
raisedButton,
],
),
);
}
}
class MessageContainer extends StatelessWidget {
const MessageContainer();
@override
Widget build(BuildContext context) {
return Text(
'You have pushed the button this many times:',
);
}
}

Note: we will not be able to do like this for widget with method:

return const RaisedButton(
onPressed: _incrementCounter,
child: const Text("Increment"),
);

as _incrementCounter is not a static method or not a constant so we can not be able to declare RaisedButton as constant but what we can do is assign it to a variable when it’s null and return when it’s not null.

issue link to read for more details of constant function literals: https://github.com/dart-lang/sdk/issues/4596

It may not be bad to optimize this level as in big apps it’s going to be a bad performance issue if we don’t do it regularly. So, after every screen design check how many times widget is rebuilding and if it needs to rebuild or not.

I hope you liked it. I will be back with other performance issues like this to explain more tools like Observatory.

There are other issues like the build method gets called even if a widget or screen is not visible to the user. read it from here:

  1. Build method called multiple times
  2. Flutter: My FutureBuilder Keeps Firing!

Many articles out there with the same problem so I would like you to keep a distance from nasty problems like this.

Check our part 2 from below link:

Do you know you can press the clap👏 button 50 times? The higher you go, the more it motivates me to write more stuff for you guys!

Hello, I am Parth Dave. A noob developer and noob photographer. You can find me on Linkedin or stalk me on GitHub or maybe follow me on Twitter?

Have a nice fluttery day!

--

--

Dave Parth
Globant
Writer for

Developer, Photographer. Flutter and Automation enthusiast.