What is the difference between StatefullWidget and StatelessWidget regards to Performance? - flutter

Is there a Performance impact if we just use StatefullWidget over the StatelessWidget it vice-versa?
In my point of view, we just use StatefullWidget for things like update part of the UI using setState(), have a way to setup some code in the initState() and dispose things in the dispose() function. So when I don't need those things I go ahead and use StatelessWidget.
But what is the real performance impact between these two most used widgets?

Performance-wise, a StatelessWidget is almost identical to a StatefulWidget with an empty State.
Writing:
class Example extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container();
}
}
or:
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
#override
Widget build(BuildContext context) {
return Container();
}
}
won't have any visible impact on the performance of your app.
There indeed is a small gain when using StatelessWidget here. But it's ridiculously small:
The difference between them can be summarized as calling an empty function vs not calling it. It's something, but absolutely doesn't matter.
The reason being, internally the implementation of StatefulWidget and StatelessWidget is almost the same.
StatelessWidget does have all the extra life-cycles that StatefulWidget possess.
It has an "initState"/"dispose". Even a setState!
They are just not part of the public API.

What is a StatelessWidget?
A widget that does not require mutable state.
Performance considerations
The build method of a stateless widget is typically only called in three situations: the first time the widget is inserted in the tree, when the widget's parent changes its configuration, and when an InheritedWidget it depends on changes.
Sample Code
class MyWidget extends StatelessWidget {
const MyWidget ({ Key key }) : super(key: key);
#override
Widget build(BuildContext context) {
return new Container(color: const Color(0xFF00BD3A));
}
}
What is a StatefulWidget?
A widget that has mutable state.
Performance considerations
here are two primary categories of StatefulWidgets.
The first is one which allocates resources in State.initState and disposes of them in State.dispose, but which does not depend on InheritedWidgets or call State.setState. Such widgets are commonly used at the root of an application or page, and communicate with subwidgets via ChangeNotifiers, Streams, or other such objects. Stateful widgets following such a pattern are relatively cheap (in terms of CPU and GPU cycles), because they are built once then never update. They can, therefore, have somewhat complicated and deep build methods.
The second category is widgets that use State.setState or depend on InheritedWidgets. These will typically rebuild many times during the application's lifetime, and it is therefore important to minimize the impact of rebuilding such a widget. (They may also use State.initState or State.didChangeDependencies and allocate resources, but the important part is that they rebuild.)
Sample code
class YellowBird extends StatefulWidget {
const YellowBird({ Key key }) : super(key: key);
#override
_YellowBirdState createState() => new _YellowBirdState();
}
class _YellowBirdState extends State<YellowBird> {
#override
Widget build(BuildContext context) {
return new Container(color: const Color(0xFFFFE306));
}
}
Full Explanaton is given here

Related

Initialize StatefulWidget state null safe from widget constructor in Flutter

I want to have a StatefulWidget where I can pass the initial value for a non-nullable member of the widgets State from the widgets constructor.
My current solution (see below) seems to be not ideal, I see two problems with it:
The initial value has to be saved in the widget itself before passing it to the state.
The member in the sate has to be marked as late since it can only be set after initialization.
Is there a better way to initialize a StatefulWidget's state non-nullable member from a value passed to the widget constructor?
My current implementation:
class MyWidget extends StatefulWidget {
final String text;
const MyWidget({Key? key, required this.text}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late String text;
#override
void initState() {
text = widget.text;
super.initState();
}
#override
Widget build(BuildContext context) {
return Text(text);
}
}
(Not shown here, but later the text member should be changeable, that's why it is in the State)
hey there your code seems good.
but the better way is using bloc to pass and receive data.
any way . its not necessary to pass and fill data in initstate and _MyWidgetState .
you can receive your data directly in build widget As you wrote (widget.text)
here is some good things for avoid nullable
https://codewithandrea.com/videos/dart-null-safety-ultimate-guide-non-nullable-types/
You could use the constructor of State like this: _MyWidgetState(){ text=widget.text; }. The constructor will certainly be executed before initState and build methods.

Is it possible to have both a stateful widgets and a stateless widget as subtypes of another class?

I recently tried to create an abstract widget, that has then both a stateless and a stateful implementation, which both can be accessed via factory-methods.
Below I added a minimal example of the only real working solution I have figured out that works for my use case, but it leaves me with some things to be desired.
For example with this solution, I have to declare and override every variable in the sub-classes, while I would really like to rely on the fact that they are subtypes and implicitly have those variables.
Has anyone of you ever needed to do a similar thing? Have you worked out a different approach?
For those concerned about as to why I would need this: I wanted to make a singular Button-Class for my App, that then has different implementations for specific styles of buttons (regular button, a 'striped' button, a button that 'loads' as the user scrolls down a page and becomes active once the user reached the end of the page, etc.). That way I could then simply call 'Button.implementation' wherever i needed a specific button, and have all the button-related Code in the same place.
Cheers.
abstract class A {
final int intellect;
A(this.intellect);
factory A.giveMeB(int intellect) {
return _B(intellect);
}
factory A.giveMeC(int intellect) {
return _C(intellect);
}
}
class _B extends StatelessWidget implements A {
#override
final int intellect;
_B(this.intellect);
#override
Widget build(BuildContext context) {
return SizedBox.shrink();
}
}
class _C extends StatefulWidget implements A {
#override
final int intellect;
const _C(this.intellect, {Key key}) : super(key: key);
#override
_CState createState() => _CState();
}
class _CState extends State<_C> {
#override
Widget build(BuildContext context) {
return Container();
}
}

Class marked as #immutable, instance field not final using StatefulWidget

I have a Stateless widget called ToggleButtonsList and one of my instance fields, isSelectedType, is not set to final. This is the warning I am receiving because of this:
"This class (or a class that this class inherits from) is marked as '#immutable', but one or more of its instance fields aren't final: ToggleButtonsList.isSelectedType"
Here is a portion of my code:
class ToggleButtonsList extends StatefulWidget {
ToggleButtonsList({this.type, this.stringList});
final String type;
final List<String> stringList;
List<bool> isSelectedType = [];
#override
_ToggleButtonsListState createState() => _ToggleButtonsListState();
}
class _ToggleButtonsListState extends State<ToggleButtonsList> {
#override
Widget build(BuildContext context) {
}
}
My question: I thought instance fields needed to be set to final only for Stateless widgets, NOT Stateful Widgets. Is this true? Is this a warning I should worry about since I'm not using a StatelessWidget or can I ignore it? My app seems to be working perfectly fine when I ignore the warning.
Reading the "or a class that this class inherits from" part of the warning made me try searching my project for any StatelessWidgets this class may inherit from and the only StatelessWidget I have in my project is from my main.dart :
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
primaryColor: Colors.blueGrey,
scaffoldBackgroundColor: Colors.blueGrey),
home: PriceScreen(),
);
}
}
Changing my MyApp class to a StatefulWidget didn't get rid of the warning.
I think your mixing State and StatefulWidget class. The Widget class itself is immutable and both StatelessWidget and StatefulWidget extends from Widgetclass.
In your specific case, isSelectedType variable can be final, because final collections can grow or shrink. Only constant collections won't allow you to grow or shrink.
What you need to do:
class ToggleButtonsList extends StatefulWidget {
ToggleButtonsList({this.type, this.stringList});
final String type;
final List<String> stringList;
#override
_ToggleButtonsListState createState() => _ToggleButtonsListState();
}
class _ToggleButtonsListState extends State<ToggleButtonsList> {
List<bool> isSelectedType = [];
#override
Widget build(BuildContext context) {
}
}
Both stateful and stateless widgets need to be immutable.
This is enforced by #immutable on Widget class.
See Flutter: Mutable fields in stateless widgets:
Stateless widgets should only have final fields, with no exceptions. Reason: When the parent widget is rebuilt for some reason (screen rotation, animations, scrolling...), the build method of the parent is called, which causes all widgets to be reconstructed.
Classes the extend StatefulWidget must follow the same rule, because those are also reconstructed. Only the State, which can contain mutable fields, is kept during the lifetime of widget in the layout tree.

Assigning InheritedWidget in build-Method

Let A be an InheritedWidget, that I can get throughout the whole app by calling A.of(context).
If I have a StatefulWidget, what is the better option (in terms of performance or code quality):
A)
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
A a;
#override
Widget build(BuildContext context) {
a ??= A.of(context);
return Container();
}
}
B)
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
#override
Widget build(BuildContext context) {
final a = A.of(context);
return Container();
}
}
I have never seen someone using Option A), so I am wondering. I prefer Option A) because every method in the _TestState class can use the a-Object easily and it is also assigned only once in the build method.
Option B is likely enough if you keep widgets small. It won't be great if you have many methods that depend on the inherited widget.
Reading option A brings up questions in my mind like
"You're caching A, do you care if A changes up in the tree?"
"Is A needed outside of build?"
"If so, why? Do we know it will be initialized at that point?"
"If not, why is it an instance field?"
Both options work though.
In terms of code quality a third option is to apply the dependency inversion principle by making A a parameter to the widget.
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({#required this.a});
final A a;
...
}
Then callers can create it with MyStatefulWidget(a: A.of(context)). This reads better than option A, though, granted, they're not equivalent.
I'm not aware of performance differences considerable enough to discuss here.

Why build method isn't defined inside StatefulWidget?

I'm currently learning Flutter. I tried to deep dive into Flutter Widget life-cycle, and I wonder why StatefulWidget are written like this :
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
// initState
// setState
// ...
#override
Widget build(BuildContext build) {
...
}
}
but not :
class Example extends StatefulWidget {
// initState
// setState
// ...
#override
Widget build(BuildContext build) {
...
}
}
I think the latter makes the source simple. But I don't know why they're using the former style ?
The reason why StatefulWidget uses a separate State class and not having build method inside its body is because all fields inside a Widget are immutable, and this includes all its sub-classes.
You might have noticed that StatelessWidget has its build and other associated methods defined inside it, but that was possible due to the nature of StatelessWidget which is rendered completely using the provided info, and doesn't expect any future change in its State.
In the case of StatefulWidget, State information occasionally change (or expected to change) during the course of the app, thus this information isn't suitable for storage in a final field (build) to satisfy Widget class conditions (all fields are immutable). That's why State class is introduced. You just have to override the createState function to attach your defined State to your StatefulWidget, and let all that change happens in a separate class.