ожидание завершения асинхронной функции - PullRequest
0 голосов
/ 05 июня 2019

Я хочу прочитать некоторые тексты и сохранить их текст в массиве.Но так как мне нужен этот массив для моего графического интерфейса, он должен ждать, пока все не будет сделано.

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)

Но когда я запускаю этот код, Finished не обновляется (я думаю, потому что это происходит потому, что цикл while работает наосновной поток и, следовательно, асинхронная функция не может выполняться одновременно)

Я мог бы сделать это, просто подождав, но это не очень хорошее решение:

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

Как теперь я могу просто подождать, пока все эти асинхронные функции не завершатся?

(извините, я новичок во Флаттере)

Ответы [ 2 ]

0 голосов
/ 06 июня 2019

Используйте 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();
       }
));
0 голосов
/ 05 июня 2019

Одна вещь, которую вы могли бы сделать, это использовать виджет с отслеживанием состояния и режим загрузки. Когда страница инициализируется, вы устанавливаете представление в качестве модального режима загрузки, а затем вызываете функцию, которая получает данные и заполняет данные, используя заданное состояние. Когда вы закончите / когда вы уверены, что окончательные данные были загружены, тогда вы устанавливаете загрузку на false. Смотрите пример ниже:

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.

      ]
      )      
    ]))
}

}


Вы также можете установить поля начальных данных на пустые значения и использовать набор состояний, чтобы дать им их действительные значения при получении данных. так например

string myvalue = " ";

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



//then  
  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;
       myValue = onValue.data['val'];
      _loading = false;
    });
   })
  }



Дайте мне знать, если это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...