Reputation: 19588
I'm having an hard time trying to figure out how to update a piece of a view based on a child view "event"... let me explain:
I have a screen which is composed by a Scaffold
, having as a body
a custom widget which calls a rest api to get the data to display (it makes use of a FutureBuilder), then it dispatch a Notification (which basically wraps the Flutter's AsynchSnapshot) that should be used in order to update the floatingActionButton
(at least in my mind :P).
This is the build
method of the screen:
@override
Widget build(BuildContext context) {
return NotificationListener<MyNotification>(
onNotification: onMyNotification,
child: Scaffold(
appBar: MyAppBar(),
body: MyRemoteObjectView(),
floatingActionButton: MyFloatingButton(),
),
);
}
The view is rendered perfectly, the data is retrieved from the server and displayed by MyRemoteObjectView
and the notification is successfully dispatched and received, BUT as soon as I call setState()
in my callback, I get the exception:
setState() or markNeedsBuild() called during build.
This is the callback (defined in the same class of the build
method above):
bool onMyNotification(MyNotification notification) {
AsyncSnapshot snapshot = notification.snapshot;
if (snapshot.connectionState == ConnectionState.done) {
setState(() {
// these flags are used to customize the appearance and behavior of the floating button
_serverHasBeenCalled = true;
_modelDataRetrieved = snapshot.hasData;
});
}
return true;
}
This is the point in which I send the notification (build method of MyRemoteObjectView
's state):
@override
Widget build(BuildContext context) {
return FutureBuilder<T>(
future: getData(),
builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
MyNotification(snapshot).dispatch(context);
// ...
The point is: how and when should I tell Flutter to redraw the floating button (and/or other widgets)? (because of course without the setState
I don't have the exception but the button is not refreshed)
Am I getting the whole thing wrong? Is there an easier way to do it? Let me know
Upvotes: 0
Views: 3124
Reputation: 9903
After FutureBuilder is built, it waits for future to return a value. After it is complete, you're calling setState and then FutureBuilder would be built again and so on, resulting in infinite repaint loop.
Are you sure that you need FutureBuilder and NotificationListener in this case? You should probably do it in initState of your StatefulWidget like this:
@override
void initState() {
super.initState();
getData().then((data) {
setState(() {
_serverHasBeenCalled = true;
_modelDataRetrieved = true;
});
});
}
You can also store Future in a state and pass it to FutureBuilder.
Upvotes: 2