通过在NotificationListener回调中调用setState,在构建期间调用Flutter异常`setState()或markNeedsBuild()

时间:2019-10-30 11:01:32

标签: flutter dart

我很难尝试根据子视图“事件”来更新视图的一部分...让我解释一下:

我有一个由Scaffold组成的屏幕,其中有一个自定义窗口小部件,它作为body,该窗口小部件调用rest api来获取要显示的数据(它使用了{{3} }),然后分派一个FutureBuilder(基本上包裹了Flutter的Notification)来更新floatingActionButton(至少在我看来:P)。 >

这是屏幕的build方法:

  @override
  Widget build(BuildContext context) {
    return NotificationListener<MyNotification>(
      onNotification: onMyNotification,
      child: Scaffold(
        appBar: MyAppBar(),
        body: MyRemoteObjectView(),
        floatingActionButton: MyFloatingButton(),
      ),
    );
  }

该视图完美呈现,从服务器检索数据并由MyRemoteObjectView显示,并且成功分派和接收了通知,但是一旦我在回调中调用setState(),我就会得到例外:

  在构建过程中调用

setState()或markNeedsBuild()。

这是回调(在上面的build方法的同一类中定义):

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

这是我发送通知的地方(MyRemoteObjectView状态的构建方法):

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<T>(
      future: getData(),
      builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
        MyNotification(snapshot).dispatch(context);
        // ...

关键是:我应该告诉Flutter重画浮动按钮(和/或其他小部件)的方式是如何何时? (因为当然没有setState,我没有例外,但是按钮没有刷新)

我把整个事情弄错了吗?有更简单的方法吗?让我知道

1 个答案:

答案 0 :(得分:1)

FutureBuilder 生成后,它会等待将来返回值。完成后,您将调用 setState ,然后将再次构建 FutureBuilder ,依此类推,从而导致无限的重画循环。

您确定在这种情况下需要FutureBuilder和NotificationListener吗?您应该像这样在StatefulWidget的 initState 中执行此操作:

@override
void initState() {
  super.initState();

  getData().then((data) {
    setState(() {
      _serverHasBeenCalled = true;
      _modelDataRetrieved = true;
    });
  });
}

您还可以将 Future 存放在一个状态中,并将其传递给 FutureBuilder