Created
December 2, 2024 21:20
-
-
Save ultraon/3d39d40f08d79c3c4e9316f127e5d146 to your computer and use it in GitHub Desktop.
The sample shows that the const widget can be skipped by Flutter for rebuilding.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:flutter_bloc/flutter_bloc.dart'; | |
class DemoPage extends StatelessWidget { | |
const DemoPage({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
return BlocProvider( | |
create: (ctx) => DependentCounterCubit(), | |
child: const Scaffold( | |
body: DemoView(), | |
), | |
); | |
} | |
} | |
class DemoView extends StatelessWidget { | |
const DemoView({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
print('DemoView build, $hashCode'); | |
final state = context.watch<DependentCounterCubit>().state; | |
return Center( | |
child: Column( | |
mainAxisAlignment: MainAxisAlignment.center, | |
children: <Widget>[ | |
const CounterText1(), | |
CounterText2('${state.counterTwo}'), | |
const SizedBox.square(dimension: 20), | |
FilledButton( | |
onPressed: context.read<DependentCounterCubit>().incrementOne, | |
child: const Text('Increment One'), | |
), | |
FilledButton( | |
onPressed: context.read<DependentCounterCubit>().incrementTwo, | |
child: const Text('Increment Two'), | |
), | |
], | |
), | |
); | |
} | |
} | |
// This class is only created for tagging it in the Widget Performance view | |
class CounterText1 extends StatelessWidget { | |
const CounterText1({super.key}); | |
@override | |
Widget build(BuildContext context) { | |
print('CounterText1 build, $hashCode'); | |
final counterText = context.select( | |
(DependentCounterCubit c) => c.state.counterOne, | |
); | |
return Text( | |
'Text1: $counterText', | |
style: Theme.of(context).textTheme.titleLarge, | |
); | |
} | |
} | |
// This class is only created for tagging it in the Widget Performance view | |
class CounterText2 extends StatelessWidget { | |
const CounterText2(this._text, {super.key}); | |
final String _text; | |
@override | |
Widget build(BuildContext context) { | |
print('CounterText2 build, $hashCode'); | |
return Text( | |
'Text2: $_text', | |
style: Theme.of(context).textTheme.titleLarge, | |
); | |
} | |
} | |
// CUBIT SAMPLE | |
typedef DependentCounterState = ({int counterOne, int counterTwo}); | |
class DependentCounterCubit extends Cubit<DependentCounterState> { | |
DependentCounterCubit() : super((counterOne: 0, counterTwo: 0)); | |
void incrementOne() { | |
emit((counterOne: state.counterOne + 1, counterTwo: state.counterTwo)); | |
} | |
void incrementTwo() { | |
emit((counterOne: state.counterOne, counterTwo: state.counterTwo + 1)); | |
} | |
} |
!!! PAY ATTENTION !!!
When I click on the "Increment One" button it shows:
Click 1:
DemoView build, 301182698
CounterText1 build, 575811888 // <------------- the instance is the same, but the `build` method is called.
CounterText2 build, 794060487
Click 2:
DemoView build, 301182698
CounterText1 build, 575811888 // <------------- the instance is the same, but the `build` method is called.
CounterText2 build, 569557191
When I click on the "Increment Two" button it shows:
Click 1:
DemoView build, 301182698
// ----------- CounterText1 isn't rebuilt
CounterText2 build, 210843644
Click 2:
DemoView build, 301182698
// ----------- CounterText1 isn't rebuilt
CounterText2 build, 288415978
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The
const
keyword significantly impacts widget performance, especially noticeable during numerous rebuilds across many widgets.Here are some clarifications:
Using
const
can lead to performance improvements because it allows Flutter to reuse instances of immutable widgets across multiple rebuilds. This is particularly beneficial in complex UIs with many static elements.There is a common confusion between “building” and “instantiating” in the official documentation that could be clarified. The term “building” often refers to invoking the build method, which describes the widget tree. In contrast, “instantiating” refers to creating an instance of a widget. Although a
const
widget can be rebuilt multiple times, its instance remains unchanged, thus saving on allocation and reducing garbage collection overhead.It’s crucial to understand that
const
is effective in all build modes (debug, profile, and release). The Dart VM optimizes performance by reusing const objects wherever possible, not just in release mode.const
widgets if their descendant widgets are not marked as dirty. For instance, if a parent widget is listening to a state change and contains a Column with aconst
widget as a child, and neither the child nor any descendants depend on the changed state, then theconst
widget will not be rebuilt. This selective rebuilding helps in further enhancing performance by avoiding unnecessary widget tree rebuilds.const
Instances:const
widget creates a single, canonical instance when instantiated with the same parameters. This can be visualized as a cache where each unique set of parameters stores one instance of the widget.const
instances of the same widget class, each differentiated by its parameters.This distinction underscores the importance of
const
in managing memory efficiency and performance in Flutter applications. Both StatelessWidget and StatefulWidget can benefit fromconst
constructors, with mutable state managed within the State.Summary:
const
avoids re-instantiation of theconst
widget with the sameconst
params, the instance is resolved during compilation time and it doesn't need to be collected by GCbuild
method of theconst
widget during the re-building phase in case the child widgets are not marked as dirty, so, they don't need to be rebuilt