等待异步功能完成

时间:2019-06-05 15:08:05

标签: asynchronous flutter

我想阅读一些txt并将其文本存储在数组中。但是因为我的GUI需要这个数组,所以应该等到所有操作完成。

Future<String> getFileData(String path) async {
    return await rootBundle.loadString(path);
  }

  int topicNr = 3;
  int finished = 0;
  for (int topic = 1; topic <= topicNr; topic++) {
    getFileData('assets/topic' + topic.toString() + '.txt').then(
      (text) {
        topics.add(text);
      },
    ).whenComplete(() {
      finished++;
    });
  }

while (finished < topicNr)

但是当我运行这段代码时,finish不会更新(我认为是因为while循环在主线程上运行,因此异步功能不能同时运行)

我可以通过等待来做到这一点,但这并不是一个好的解决方案:

Future.delayed(const Duration(milliseconds: 10), () {
    runApp(MaterialApp(
      title: 'Navigation Basics',
      home: MainMenu(),
    ));
  });

我现在如何才能等到所有这些异步功能完成?

(对不起,我是Flutter的新手)

2 个答案:

答案 0 :(得分:0)

您可以做的一件事是使用有状态的小部件和加载模式。页面初始化后,将视图设置为加载模式,然后调用获取数据并使用set状态填充数据的函数。完成/确定最终数据已加载后,将加载设置为false。请参见下面的示例:

{1: {}, 2: {}, 3: {}, 4: {}, 5: {}}

您还可以将初始数据的字段设置为空值,并使用set状态在获取数据时为其提供实际值。 例如

class Page extends StatefulWidget {
  page();
  @override
  State<StatefulWidget> createState() => new _Page();
}


class _Page extends State<Page>{

 bool _loading = true; //used to show if the page is loading or not

   @override
  void initState() {
  getFileData(path); //Call the method to get the data
  super.initState();
  }

  Future<String> getFileData(String path) async {
    return await rootBundle.loadString(path).then((onValue){
        setState(() { //Call the data and then set loading to false when you are done 
      data = on value.data;
      _loading = false;
    });
   })
  }


  //You could also use this widget if you want the loading modal ontop your page.
  Widget IsloadingWidget() {
    if (_loading) {
      return Stack(
        children: [
          new Opacity(
            opacity: 0.3,
            child: const ModalBarrier(
              dismissible: false,
              color: Colors.grey,
            ),
          ),
          new Center(
            child: new CircularProgressIndicator(
              valueColor:
                  new AlwaysStoppedAnimation<Color>(Colors.green),
              strokeWidth: 4.0,
            ),
          ),
        ],
      );
    } else {
      return Container();
    }
  }

 @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Stack(
      children: <Widget>[
//If loading, return a loading widget, else return the page.
       _loading ? 
       Container(
         child: Center(
           child: CircularProgressIndicator(
            valueColor: new AlwaysStoppedAnimation<Color>(
             Colors.blue))))
       :Column(
        children:<Widget>[
         //Rest of your page.

      ]
      )      
    ]))
}

}


让我知道是否有帮助。

答案 1 :(得分:0)

使用FutureBuilder等待API调用完成,然后再构建widget

请参见以下示例:https://flutter.dev/docs/cookbook/networking/fetch-data

runApp(MaterialApp(
  title: 'Navigation Basics',
  home: FutureBuilder(
     future: getFileData(),
     builder: (context, snapshot) {
       if (snapshot.hasData) {
         return MainMenu()
       } else {
          return CircularProgressIndicator();
       }
));