在initState中初始化一次数据,并在数据就绪后调用setState导致异常

h19*_*103 5 flutter

由于flutter在不同的条件下多次调用build方法,因此为了避免多次获取数据,我在initState中初始化了数据。

我想在数据准备好后重新构建窗口小部件。

这是我的代码:

class Test extends StatefulWidget {

  @override
  _TestState createState() => new _TestState();

}

class _TestState extends State<Test> {

  Data data;
  bool dataReady = false;

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

    getData(context).then((Data data) async {
      setState(() {
        dataReady= true;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    if (dataReady) {
      return createMainContent(context);
    } else {
      return new Container();
    }
  }

}
Run Code Online (Sandbox Code Playgroud)

但是,它导致以下异常:在_TestState.initState()完成之前调用了InheritFromWidgetOfExactType(_InheritedProvider)或InheritFromElement()。

我可以知道我在这里做错什么吗?

当我将以下行添加到getData(context)的实现中时

     await Future.delayed(new Duration(milliseconds: 300));
Run Code Online (Sandbox Code Playgroud)

,不会发生例外。

谢谢!

Jav*_*ana 18

对于以后来这里的每个人

最好使用类的@override void didChangeDependencies ()方法State

文档

这个方法也会在 initState 之后立即调用。从此方法调用 BuildContext.inheritFromWidgetOfExactType 是安全的。

但请务必检查您是否已经执行了初始化

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  if (bloc == null) { // or else you end up creating multiple instances in this case.
    bloc = BlocProvider<MyBloc>.of(context);
  }
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*cel 12

编辑:下面更好的答案。


显然,您无法访问getData(context)期间initState(更具体地说:在完成之前)。

我相信,原因是它getData试图InheritedWidget在树中查找祖先,但树刚刚被构建(您的小部件是在父小部件的 期间创建的build)。

显而易见的解决方案是将getData的查找延迟到稍后的时间点。有几种方法可以实现:

  • 将查找延迟到以后。scheduleMicrotask应该工作正常。
  • 在第一次build通话时查看它。您可以将一个isInitialized字段设置为falseand in you build,例如:

    if (!isInitialized) {
      isInitialized = true;
      // TODO: do the getData(...) stuff
    }
    
    Run Code Online (Sandbox Code Playgroud)


MJ *_*tes 9

另一种方法是将其放在和PostFrameCallback之间。initStateBuild

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) => getData());
    super.initState();
  }

  getData() async {

  }
Run Code Online (Sandbox Code Playgroud)