Flutter: In which order should super() be called with dispose() and initState()? (example with a focusNode) [duplicate] - flutter

I am confused as to where to call the super.initSate() in Flutter? In some code examples, it's called at the beginning and in others at the end. Is there a difference?
I have tried to google this but haven't found any explanation on the position of this function call.
Which one is correct?
void initState() {
super.initState();
//DO OTHER STUFF
}
or
void initState() {
//DO OTHER STUFF
super.initState();
}

It does matter for mixins (and because of that for you as well)
It is a paradigm in the Flutter framework to call the super method when overriding lifecycle methods in a State. This is why even deactivate has a mustCallSuper annotation.
Additionally, some mixins expect that you call the super methods of those lifecycle methods at a particular point in the function.
This means that you should follow the documentation and call super.dispose at the end of your dispose method because mixins on State in the framework expect that this is the case.
For example: TickerProviderStateMixin and SingleTickerProviderStateMixin assert super.dispose at the end:
All Tickers must [..] be disposed before calling super.dispose().
Another example: AutomaticKeepAliveMixin executes logic in initState and dispose.
Conclusion
Start your initState with super.initState and end your dispose with super.dispose if you want to be on the easy and safe side adding mixins to your State.
Furthermore, follow the documentation for other lifecycle methods (any method you overwrite in State) because the framework will expect that you call the super methods as described in the documentation.
Thus, the following is what you should do:
#override
void initState() {
super.initState();
// DO YOUR STUFF
}
#override
void dispose() {
// DO YOUR STUFF
super.dispose();
}
However, it does not really matter for State, which I will explain in the following and even for mixins, it only matters for assertions judging from what I could find - so it would not affect your production app.
It does not matter for State
I think that the previous two answers from Pablo Barrera and CopsOnRoad are misleading because the truth of the matter is that it really does not matter and you do not need to look far.
The only actions that super.initState and super.dispose take in the State class itself are assertions and since assert-statements are only evaluated in debug mode, it does not matter at all once build your app, i.e. in production mode.
In the following, I will guide you through what super.initState and super.dispose do in State, which is all the code that will be executed when you have no additional mixins.
initState
Let us look exactly what code is executed in super.initState first (source):
#protected
#mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
As you can see, there is only a lifecycle assertion and the purpose of it is to ensure that your widget works correctly. So as long as you call super.initState somewhere in your own initState, you will see an AssertionError if your widget is not working as intended. It does not matter if you took some prior action because the assert is only meant to report that something in your code is wrong anyway and you will see that even if you call super.initState at the very end of your method.
dispose
The dispose method is analogous (source):
#protected
#mustCallSuper
void dispose() {
assert(_debugLifecycleState == _StateLifecycle.ready);
assert(() {
_debugLifecycleState = _StateLifecycle.defunct;
return true;
}());
}
As you can see, it also only contains assertions that handle debug lifecycle checking. The second assert here is a nice trick because it ensures that the _debugLifecycleState is only changed in debug mode (as assert-statements are only executed in debug mode).
This means that as long as you call super.dispose somewhere in your own method, you will not lose any value without mixins adding additional functionality.

super.initState() should always be the first line in your initState method.
From docs:
initState(): If you override this, make sure your method starts with a call to
super.initState().

As you could see in the classes from the framework, you should do everything after the widget is initialized, meaning after super.initState().
I case of dispose would be logically in the other way, first do everything and then call super.dispose().
#override
void initState() {
super.initState();
// DO STUFF
}
#override
void dispose() {
// DO STUFF
super.dispose();
}

initState called up by default whenever a new stateful widget is added into a widget tree.
Now the super.initState performs the default implementation of the base class of your widget.If you call anything before super.initState that depends on the base class then this might cause problem.
That's why it's recommended that you call initState in this fashion:
#override
void initState() {
super.initState();
// DO STUFF
}

Related

Prevent memory leak in Flutter

I was trying to make my function works with a Timer to fetch a list of actions from Database and display them without leaving the screen and re-enter again.
I tried the following :
void initState() {
super.initState();
Timer.periodic(timeDelay, (Timer t) => fetchFournisseurs());
}
It's working now , but my debug console is showing some infos :
State.setState.<anonymous closure> (package:flutter/src/widgets/fr<…>
[VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: setState() called after dispose(): _listeDocumentState#c0f9f(lifecycle state: defunct, not mounted)
This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback.
The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
Is there a better way to make it and prevent memory leak or anything bad ?
Thank you.
All of the information is in the error message itself.
This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build).
For example if you navigate to a page containing this widget, and then close that page, the widget would no longer be in the widget tree, but the Timer you created is still running periodically.
This error can occur when code calls setState() from a timer or an animation callback.
Presumably fetchFournisseurs is calling setState.
The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback.
In other words your state class should do something along these lines.
class _ExampleState extends State<Example> {
final Duration timeDelay = ...;
// Create a variable to hold the timer.
Timer? _timer;
#override
void initState() {
super.initState();
// Assign timer to the variable.
_timer = Timer.periodic(timeDelay, (Timer t) => fetchFournisseurs());
}
#override
void dispose() {
// Cancel the timer in the dispose() callback.
_timer?.cancel();
super.dispose();
}
void fetchFournisseurs() {
// presumably fetchFournisseurs calls setState at some point.
setState(() {
...
});
}
#override
Widget build(BuildContext context) {
return ...;
}
}
Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
Which means to do the following.
void fetchFournisseurs() {
// check if the widget is mounted before proceeding
if (!mounted) return;
setState(() {
...
});
}
This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
Another reminder to cancel the Timer in dispose to avoid memory leaks.

Does autoDispose in riverpod works same as dispose lifecycle in Flutter?

Does autoDispose in Riverpod's StateProvider disposes controllers?
Does both the following statements works similarly?
final _controller = StateProvider.autoDispose((ref) => PageController());
or
final _controller = PageController();
#override
void dispose() {
_controller.dispose();
super.dispose();
}
autoDispose modifier, as the name suggests, disposes call of the resources when the provider is not used, it simply frees up memory without us specifying any dispose function.
One example that may help you for example when you navigate into another page in which you have a provider with autoDispose, if you go back to your first page your provider data will reset, without autoDispose, everything will be saved.

How to dispose of an unmounted Widget in Flutter?

I am writing a flutter app and if you already started it once, I dont want the user to see the Intro Screen again
In my MaterialApp:
home: firstStart ? DeviceSelection() : StartScreen()
firstStart is a boolean, if it is the first start, it should start the App with the StartScreen() and if its not, it should go straight to DeviceSelection(). That all works fine, but my problem is the following error:
Error: This widget has been unmounted, so the State no longer has a context (and should be considered defunct).
Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.
I think it starts StartScreen too, even if firstStart is false, because it has to get its value out of the shared preferences, because I see it pop up shortly sometimes.
I already tried some stuff I found, like writing a dispose method:
#override
void dispose() {
super.dispose();
}
or
if (!mounted) {
Navigator.pop(context);
}
in a method that I call after the screen starts, but it doesnt work either. Any ideas what I could do to get rid of this error? Thanks
mb set a flag, like:
bool lookedIntro = false; // if user look it first
and then use:
#override
void initState() {
// take data flag from database or somewhere else (file)
// and check it
}
and also read about initState() more

When the dispose() method should be executed?

When the dispose() method should be executed?
For instance, there are two widgets:
Statefull Widget 1
Widget 2
The widget 1 has the dispose() method, because this widget intialize admob add, so we should implement there dispose with
_bannerAd?.dispose();
Now, let's imagine a situation. I go from W1 to W2 and then back to W1.
Should not the dispose() has to be executed? I have modeled such navigation and the dispose() was not execured.
Then I press back button on emulator (to return to the W2) and now the dispose was executed(!), why it was executed in this case and was not when we made navigator push the widget 2?
it is because, .pop() will remove the route from stack where .push() will not, removing from stack essentially means disposing.
(pop happens when you come back W2)
You can put the _bannerAd?.dispose(); part inside of the dispose callback of the statefullWidget:
/* inside the statefullWidget class */
#override
dispose(){
super.dispose();
_bannerAd?.dispose();
}
Flutter will take care of the rest.

Should I call super.initState at the end or at the beginning?

I am confused as to where to call the super.initSate() in Flutter? In some code examples, it's called at the beginning and in others at the end. Is there a difference?
I have tried to google this but haven't found any explanation on the position of this function call.
Which one is correct?
void initState() {
super.initState();
//DO OTHER STUFF
}
or
void initState() {
//DO OTHER STUFF
super.initState();
}
It does matter for mixins (and because of that for you as well)
It is a paradigm in the Flutter framework to call the super method when overriding lifecycle methods in a State. This is why even deactivate has a mustCallSuper annotation.
Additionally, some mixins expect that you call the super methods of those lifecycle methods at a particular point in the function.
This means that you should follow the documentation and call super.dispose at the end of your dispose method because mixins on State in the framework expect that this is the case.
For example: TickerProviderStateMixin and SingleTickerProviderStateMixin assert super.dispose at the end:
All Tickers must [..] be disposed before calling super.dispose().
Another example: AutomaticKeepAliveMixin executes logic in initState and dispose.
Conclusion
Start your initState with super.initState and end your dispose with super.dispose if you want to be on the easy and safe side adding mixins to your State.
Furthermore, follow the documentation for other lifecycle methods (any method you overwrite in State) because the framework will expect that you call the super methods as described in the documentation.
Thus, the following is what you should do:
#override
void initState() {
super.initState();
// DO YOUR STUFF
}
#override
void dispose() {
// DO YOUR STUFF
super.dispose();
}
However, it does not really matter for State, which I will explain in the following and even for mixins, it only matters for assertions judging from what I could find - so it would not affect your production app.
It does not matter for State
I think that the previous two answers from Pablo Barrera and CopsOnRoad are misleading because the truth of the matter is that it really does not matter and you do not need to look far.
The only actions that super.initState and super.dispose take in the State class itself are assertions and since assert-statements are only evaluated in debug mode, it does not matter at all once build your app, i.e. in production mode.
In the following, I will guide you through what super.initState and super.dispose do in State, which is all the code that will be executed when you have no additional mixins.
initState
Let us look exactly what code is executed in super.initState first (source):
#protected
#mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
As you can see, there is only a lifecycle assertion and the purpose of it is to ensure that your widget works correctly. So as long as you call super.initState somewhere in your own initState, you will see an AssertionError if your widget is not working as intended. It does not matter if you took some prior action because the assert is only meant to report that something in your code is wrong anyway and you will see that even if you call super.initState at the very end of your method.
dispose
The dispose method is analogous (source):
#protected
#mustCallSuper
void dispose() {
assert(_debugLifecycleState == _StateLifecycle.ready);
assert(() {
_debugLifecycleState = _StateLifecycle.defunct;
return true;
}());
}
As you can see, it also only contains assertions that handle debug lifecycle checking. The second assert here is a nice trick because it ensures that the _debugLifecycleState is only changed in debug mode (as assert-statements are only executed in debug mode).
This means that as long as you call super.dispose somewhere in your own method, you will not lose any value without mixins adding additional functionality.
super.initState() should always be the first line in your initState method.
From docs:
initState(): If you override this, make sure your method starts with a call to
super.initState().
As you could see in the classes from the framework, you should do everything after the widget is initialized, meaning after super.initState().
I case of dispose would be logically in the other way, first do everything and then call super.dispose().
#override
void initState() {
super.initState();
// DO STUFF
}
#override
void dispose() {
// DO STUFF
super.dispose();
}
initState called up by default whenever a new stateful widget is added into a widget tree.
Now the super.initState performs the default implementation of the base class of your widget.If you call anything before super.initState that depends on the base class then this might cause problem.
That's why it's recommended that you call initState in this fashion:
#override
void initState() {
super.initState();
// DO STUFF
}