When I click the raised button, the timepicker is showing up. Now, if I wait 5 seconds, for example, and then confirm the time, this error will occur: setState() called after dispose()
I literally see in the console how flutter is updating the parent widgets, but why? I don't do anything - I just wait 5 seconds?! The example below will work in a normal project, however in my project which is quite more complex it won't work because Flutter is updating the states while I am waiting... What am I doing wrong? Does anyone have a guess at what it could be that Flutter is updating randomly in my more complex project and not in a simple project?
[UPDATE]
I took a second look at it and found out it is updating from the level on where my TabBar
and TabBarView
are.
Could it have to do something with the "with TickerProviderStateMixin" which I need for the TabBarView
? Could it be that it causes the app to refresh regularly and randomly?
class DateTimeButton extends State<DateTimeButtonWidget> {
DateTime selectedDate = new DateTime.now();
Future initTimePicker() async {
final TimeOfDay picked = await showTimePicker(
context: context,
initialTime: new TimeOfDay(hour: selectedDate.hour, minute: selectedDate.minute),
);
if (picked != null) {
setState(() {
selectedDate = new DateTime(selectedDate.year, selectedDate.month, selectedDate.day, picked.hour, picked.minute);
});
}
}
@override
Widget build(BuildContext context) {
return new RaisedButton(
child: new Text("${selectedDate.hour} ${selectedDate.minute}"),
onPressed: () {
initTimePicker();
}
);
}
}
'setState() called after dispose()' - we all have seen this multiple times and it means that State object has been removed permanently from the element tree(more about it here) and its UI can not be drawn on the screen anymore.
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.
Calling setState notifies the framework that the internal state of this object has changed in a way that might impact the user interface in this subtree, which causes the framework to schedule a build for this State object.
setState is a way to dynamically change the UI. We call it inside the State Object class of the StatefulWidget. Calling setState marks the corresponding Widget dirty .
Just check boolean property mounted
of the state class of your widget before calling setState()
.
if (this.mounted) {
setState(() {
// Your state change code goes here
});
}
Or even more clean approach
Override setState
method in your StatelfulWidget
class.
class DateTimeButton extends StatefulWidget {
@override
void setState(fn) {
if(mounted) {
super.setState(fn);
}
}
}
If it is an expected behavior that the Future
completes when the widget already got disposed you can use
if (mounted) {
setState(() {
selectedDate = new DateTime(selectedDate.year, selectedDate.month, selectedDate.day, picked.hour, picked.minute);
});
}
Just write one line before setState()
if (!mounted) return;
and then
setState(() {
//Your code
});
I had the same problem and i solved changing the super constructor call order on initState()
:
Wrong code:
@override
void initState() {
foo_bar(); // call setState();
super.initState(); // then foo_bar()
}
Right code:
@override
void initState() {
super.initState();
foo_bar(); // first call super constructor then foo_bar that contains setState() call
}
To prevent the error from occurring, one can make use of the mounted
property of the State
class to ensure that a widget is mounted before settings its state:
// First Update data
if (!mounted) {
return;
}
setState(() { }
Try this
Widget build(BuildContext context) {
return new RaisedButton(
child: new Text("${selectedDate.hour} ${selectedDate.minute}"),
onPressed: () async {
await initTimePicker();
}
);
}
class MountedState<T extends StatefulWidget> extends State<T> {
@override
Widget build(BuildContext context) {
return null;
}
@override
void setState(VoidCallback fn) {
if (mounted) {
super.setState(fn);
}
}
}
Example
To prevent the error,Instead of using State use MountedState
class ExampleStatefulWidget extends StatefulWidget {
const ExampleStatefulWidget({Key key}) : super(key: key);
@override
_ExampleStatefulWidgetState createState() => _ExampleStatefulWidgetState();
}
class _ExampleStatefulWidgetState extends MountedState<ExampleStatefulWidget> {
....
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With