I am having trouble finding the source to this exception, and the app is quite complex so it is hard to show any relevant part of the code. This is my repository at the poin
This is not a thread problem. This error means that you are calling setState
during the build phase.
A typical example would be the following :
Widget build(BuildContext context) {
myParentWidgetState.setState(() { print("foo"); });
return Container();
}
But the setState call may be less obvious. For example a Navigator.pop(context)
does a setState
internally. So the following :
Widget build(BuildContext context) {
Navigator.pop(context);
return Container();
}
is a no go either.
Looking at the stacktrace it seems that simultaneously with the Navigator.pop(context)
your modal try to update with new data.
Use Timer
class,
import 'dart:async';
@override
void initState() {
super.initState();
Timer.run(() {
// You can call setState from here
});
}
Special case of using Scaffold
and Drawer
:
That fail can also happen if you try to rebuild the tree with opened Drawer
. For example if you send a message to a Bloc
that forces rebuilding of the whole page/screen.
Consider to call Navigator.pop(context)
first in your tap handler.
As a workaround wrap your code that calling setState
into WidgetsBinding.addPostFrameCallback:
WidgetsBinding.instance
.addPostFrameCallback((_) => setState(() {}));
That way you can be sure it gets executed after the current widget is built.
As the provided answer seems true, I had a work around as, in my case, it was not possible to simply remove it from the build.
I used Future.delayed(Duration.zero, () => setState(() { ... }));
instead of setState and the same for methods that may use setState as well.
EDIT: source
I faced the same issue when making a widget that need to do Navigator.pop
before returning an Widget in build
.
Let me call the code from Rémi Rousselet:
Widget build(BuildContext context) {
Navigator.pop(context);
return Container();
}
This code above would cause the error, but you could only pop becasue context
is in build
, so how to do?
Widget build(BuildContext context) {
if(datas != null) // check datas
{
SchedulerBinding.instance.addPostFrameCallback((_){ // make pop action to next cycle
Navigator.of(context).pop(datas); /*...your datas*/
});
}
return Container();
}
This method is the combination of the others, but I'm not sure If this is the best practice, If there are any errors, please leave a comment to point me out!