Flutter setState() or markNeedsBuild() called when widget tree was locked
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.
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.
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
There are couple of options used setState
inside build
method and context
on initState
Wrap your setState inside one of these
WidgetsBinding.instance.addPostFrameCallback
or Future.microTask()
or Timer.run
or Future.delayed(Duration.zero,
Example:
WidgetsBinding.instance
.addPostFrameCallback((_) {
//valueNotifier.value = _pcm; //provider
//setState
});