Does using const in the widget tree improve performance?
It is a small performance improvement, but it can add up in larger apps or apps where the view is rebuilt often for example because of animations.const
reduces the required work for the Garbage Collector.
You can enable some linter rules in analysis_options.yaml
that tell you when you should add const
because it's not inferred but would be possible like
- http://dart-lang.github.io/linter/lints/prefer_const_constructors.html
- http://dart-lang.github.io/linter/lints/prefer_const_declarations.html
- http://dart-lang.github.io/linter/lints/prefer_const_literals_to_create_immutables.html
or that reminds you when you use const
but it is inferred anyway
- http://dart-lang.github.io/linter/lints/unnecessary_const.html
See also https://www.dartlang.org/guides/language/analysis-options
In the case of Flutter, the real gain with const
is not having less instantiation.
Flutter has a special treatment for when the instance of a widget doesn't change: it doesn't rebuild them.
Consider the following:
Foo(
child: const Bar(
child: Baz()
),
)
In the case of build
method being called again (setState
, parent rebuild, Inheritedwidget
...), then due to the const
for Bar
subtree, only Foo
will see its build
method called.
Bar
will never get rebuilt because of its parent, because Flutter knows that since the widget instance didn't change, there's nothing to update.
Update: I noticed I received an upvote lately, and I must say that I'm not confident in my tests below but that's all I got. So someone better run a better test.
I've ran some test to see if it makes a difference.
The tests are heavily based on the ones done in this article.
For the tests, there are 300 containers with text inside moving randomly on the screen. Something you wouldn't see in a day to day app.
For my results there is no difference in frame per second and there is no difference in memory usage except that the Garbage collector seems to run more often when not using const. Again, the FPS were about the same.
Imo, the performance boost is negligible and sounds like preemptive optimization. However there is no deeply nested chain of widgets in the test, but I don't see how that would make a difference. The article above seems to say there is a small one, but that's not what my tests show.
I've a card like this (this is the const version):
import 'package:flutter/material.dart';
class MyCard extends StatelessWidget {
const MyCard();
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
margin: const EdgeInsets.all(8.0),
height: 100,
width: 100,
color: Colors.red,
child: const Text('Hi'),
),
);
}
}
that's rendered 300 times and moving on the screen randomly.
This is the widget that makes them move
import 'package:flutter/material.dart';
import 'dart:math';
import 'dart:async';
import './my-card.dart';
class MovingContainer extends StatefulWidget {
@override
_MovingContainerState createState() => _MovingContainerState();
}
class _MovingContainerState extends State<MovingContainer> {
final Random _random = Random();
final Duration _duration = const Duration(milliseconds: 1000);
Timer _timer;
double _top = 0;
double _left = 0;
@override
void initState() {
super.initState();
initMove();
}
void initMove() {
_timer = Timer.periodic(
_duration,
(timer) {
move();
},
);
}
void move() {
final Size size = MediaQuery.of(context).size;
setState(() {
_top = _random.nextInt(size.height.toInt() - 100).toDouble();
_left = _random.nextInt(size.width.toInt() - 100).toDouble();
});
}
@override
void dispose() {
_timer.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedPositioned(
top: _top,
left: _left,
child: const MyCard(),
duration: _duration,
);
}
}
Note: I'm new to flutter, and so are many others because it's a relatively new framework. Therefor my tests could very well be wrong, don't take it as gospel. Also don't take it as gospel when you read an article titled << Number One Perf gain on Flutter >>. I've yet to see actual proof there is a perf gain. And preemptive optimization is a sweet fallacy to fall in.