Introduction
Get better scrolling and animations, less memory consumption, and more execution speed. Boost your Flutter app performance with these 6 tips. And if you want more, I have a free ebook with additional tips for you at the end!
Here are some easy-to-use best practices for Flutter apps when it’s all about performance. Use them if you notice any problems but don’t optimize prematurely. Flutter apps are fast by default and you won’t have any trouble usually. Here is how you can boost your Flutter app performance with these 6 tips.
Also, make sure to download my free ebook about Flutter performance tips. You can find the link at the end of this article.
Prefer StatelessWidget over StatefulWidget
A StatelessWidget
is faster than a StatefulWidget
because it doesn’t need to manage state as the name implies. That’s why you should prefer it if possible. Choose a StatefulWidget
when…
▶ you need a preparation function with initState()
▶ you need to dispose of resources with dispose()
▶ you need to trigger a widget rebuild with setState()
▶ your widget has changing variables (non-final) In all other situations, you should prefer a StatelessWidget
.
⛔ Bad example
import 'package:flutter/widgets.dart';
class MyWidget extends StatefulWidget {
final String header;
final String subheader;
const MyWidget({Key? key, required this.header, required this.subheader}): super(key: key);
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
@override
Widget build(BuildContext context) {
return Column(children: [Text(widget.header), Text(widget.subheader)]);
}
}
✅ Good example
import 'package:flutter/widgets.dart';
class MyWidget extends StatelessWidget {
final String header;
final String subheader;
const MyWidget({Key? key, required this.header, required this.subheader}): super(key: key);
@override
Widget build(BuildContext context) {
return Column(children: [Text(header), Text(subheader)]);
}
}
Use builder constructors on long lists or grids
When dealing with lists or grids with many items, it is recommended to use the builder
constructors. Their advantage is that only visible elements are rendered. So if your list or grid is bigger than one device screen, you should choose this approach. For smaller lists and grids, the default constructors can also be used. This applies to all types of lists and grids like ListView, ReorderableListView, or GridView. Always check for a builder constructor and use it if possible.
✅ Good example
final List<int> _listItems = <int>[1, 2, 3, 4, 5, 6, 7, 8, 9];
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _listItems.length,
itemBuilder: (context, index) {
var item = _listItems[index];
return SizedBox(
height: 300, child: Center(child: Text(item.toString())));
}
);
}
Don’t use OpacityWidget
The Opacity
widget can cause performance issues when used with animations because all child widgets of the Opacity
widget will also be rebuilt in every new frame. It is better to use AnimatedOpacity
in this case. If you want to fade in an image, use the FadeInImage
widget. If you want to have a color with opacity, draw a color with opacity.
⛔ Bad example
Opacity(opacity: 0.5, child: Container(color: Colors.red))
✅ Good example
Container(color: Color.fromRGBO(255, 0, 0, 0.5))
Precache images and icons
Flutter contains a function precacheImage()
which can be used to reduce the loading time of images and icons. You can use it in the initState()
or didChangeDependencies()
methods to speed up image display, for example.
const List<CatImage> images = [
CatImage(width: 150, height: 150, caption: 'Watch out'),
CatImage(width: 150, height: 160, caption: 'Hmm'),
CatImage(width: 160, height: 150, caption: 'Whats up'),
CatImage(width: 140, height: 150, caption: 'Miaoo'),
CatImage(width: 130, height: 150, caption: 'Hey'),
CatImage(width: 155, height: 150, caption: 'Hello'),
];
@override
void didChangeDependencies() {
super.didChangeDependencies();
for (CatImage image in images) {
precacheImage(NetworkImage(image.url), context);
}
}
Reduce memory consumption of ListView
A ListView
has two properties (addRepaintBoundary
and addAutomaticKeepAlives
) that can lead to a high memory consumption in certain cases. They tell the ListView
to not dispose of items which are not visible on the screen at the moment. In terms of performance, this is good because scrolling is fast. But the invisible items still occupy memory space. If you have a long list of images, this can lead to a problem. The solution is to set the mentioned properties to false (they are set to true
by default).
ListView.builder(
addAutomaticKeepAlives: false,
addRepaintBoundaries: false,
…
);
Always use keys
Every widget has a key
constructor parameter and creates an element in the widget tree. A key
allows us to reuse an element instead of creating a new one. You can either use ValueKeys
or GlobalKeys
. GlobalKeys
can be tricky because there can never be multiple widgets with the same key in the widget tree. ValueKeys
on the other hand will lead to bloaty code as you need to define them for each widget.
💡 Tip
Do you want more tips? Check out my free ebook!
Boost the speed of your Flutter apps!
This ebook contains solutions to problems which are about slow app performance and high memory consumption.
Conclusion
In this article, you learned how you can boost your Flutter app performance with these 6 tips.