7

What I did :

  • I have integrated FCM (Firebase Cloud Messaging) in my flutter app.
  • I shared the context and the setState() of each page in static variables with these two lines getting called in all the build functions of my pages :
@override
Widget build(BuildContext context) {
    StaticClass.currentContext = context;
    StaticClass.currentSetState = this.setState;
    return ... ;
}
  • I created a callback to handle the coming notifications when the app is running
fcm.configure( onMessage: (){
    StaticClass.currentSetState((){
        Navigator.pushNamed(StaticClass.currentContext, "/notifications");
  });
});

What happened :

  • I got this error:
 ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══
...
setState() or markNeedsBuild() called during build.
This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets.
...

Explanations :

  • I can't update the page (by using context or calling setState()) when the framework is building
  • This problem doesn't happen when this function is called with a user interaction

What I want :

  • Is there a way to repair my code or am I doing something wrong ?

OR

  • Is there any other solution to go to another Page when onMessage() is triggered ?

OR

  • Is there a way to know when the build function completes, to setState() without any problem ?

Please Help I'm stuck here

Khalil Bz
  • 557
  • 1
  • 9
  • 24
  • 1
    We cannot call setState during building process. It’s strict especially with Stack widget because Overlay needs all calculation of layouting information at first of building. I recommend you determine to implement Rx architecture. https://www.didierboelens.com/2018/08/reactive-programming---streams---bloc/ – HeavenOSK Feb 23 '19 at 22:04
  • Thank you so much for your comment. but to help me understand more, just forget what I did, and tell me what I should do when I receive a notification from Firebase ? Something that could exist in any app (Receiving notifications). Thanks in advance – Khalil Bz Feb 23 '19 at 22:31
  • I believe you should use Redux instead of setstate for the state management – Kenneth Li Feb 24 '19 at 10:06

1 Answers1

32

You can call setState after rendering is done by adding a post frame callback with addPostFrameCallback method. This will be called only once and after build process is done.

WidgetsBinding.instance.addPostFrameCallback((_) => setState(() {}));
Miguel Ruivo
  • 16,035
  • 7
  • 57
  • 87
  • 5
    This will fire multiple times building the widgets continuously when seen in debug mode. Ultimately slows down and crash the app. – Jiten Basnet Jan 27 '20 at 17:22
  • No it won't. This is actually the correct way to scheduling a new frame after rebuilding widgets. If that is happening to you, that's probably because you are scheduling in the wrong place where it will recursively schedule new frames (for example, in the `build` method). This _should_ only be used in places that aren't dependent from widget rebuilds, such as callback methods, state methods and so on. – Miguel Ruivo Jan 28 '20 at 11:22
  • 1
    Could you please elaborate where exactly call this function? Apparently I can only call it in the build function. – U.Savas Apr 19 '20 at 22:12
  • This will cause your widget to rebuild continously thereby slowing down your application. The setState is the issue. Because you are reloading the widget each time the widget finishes building. – Yonko Kilasi Oct 05 '20 at 07:24
  • 5
    You _can_ call this method in multiple places such as `initState()`, `onTap()` callbacks and so on. You _can’t_ call it on your `build()` method as it will recursively schedule rebuilds. – Miguel Ruivo Oct 25 '20 at 12:25
  • This is the correct answer. If calling `setState()` inside the callback causes repeated builds, then the code inside the `setState()` is the problem. It must not modify anything outside the current widget's `State` instance. If only the state of the current widget is modified, then a new frame will **not** be created again, but the widgets will be rendered with the new state. If you try to modify state in a widget higher up in the tree that causes a rebuild, then this will fail. – Ber Apr 13 '21 at 08:41