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
          });