web-dev-qa-db-ja.com

forEachループにリストが入力される前に、非同期呼び出しが返されます

デバイスからファイル名のリストを取得し、ファイルを読み取ってリストを作成するルーチンがあります。ただし、呼び出しルーチンは常にゼロ項目で戻ります。ファイル名を印刷したので、それらが存在することはわかっていますが、ファイルを読み取る前に非同期が戻っているようです。 HTTP呼び出しを行うときに同様のコードを使用しました。しかし、ここで何かが原因で、ルーチンは完了していなくてもリストを返します。おそらく、私が間違った時間にそれを呼んでいる可能性がありますか?ここでretrieveItemsを呼び出しています:

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

最終的には更新ボタンが表示されますが、今のところ、リストにファイルのデータを入力するだけです...

--------------------

呼び出し先

Future<List<String>> readHeaderData() async {
  List<String> l = new List();
  List<String> files = await readHeaders(); // Gets filenames
  files.forEach((filename) async {
    final file = await File(filename);
    String contents = await file.readAsString();
    User usr = User.fromJson(json.decode(contents));
    String name = usr.NameLast + ", " + usr.NameFirst;
    print(name);
    l.add(name);
  }
  return l;

発信者

void retrieveItems() async {
  LocalStorage storage = new LocalStorage();
  await storage.readHeaderData().then((item) {
      try {
        if ((item != null ) &&(item.length >= 1)) {
          setState(() {
            users.clear();
            _users.addAll(item);
          });
        } else {
          setState(() {
            _users.clear();
            final snackbar = new SnackBar(
              content: new Text('No users found.'),
            );
            scaffoldKey.currentState.showSnackBar(snackbar);
          });
        }
      } on FileNotFoundException catch (e) {
        print(e.toString()); //For debug only
        setState(() {
          _users.clear();
        });
      });
    }
  });
8
Jerry

このコード

_Future<List<String>> readHeaderData() async {
  List<String> l = new List();
  List<String> files = await readHeaders(); // Gets filenames
  files.forEach((filename) async {
    final file = await File(filename);
    String contents = await file.readAsString();
    User user = User.fromJson(json.decode(contents));
    String name = user.NameLast + ", " + user.NameFirst;
    print(name);
    l.add(name);
  }
  return l;
}
_

リストlを返し、asyc forEach(...)コールバックを処理します

に変更した場合

_Future<List<String>> readHeaderData() async {
  List<String> l = new List();
  List<String> files = await readHeaders(); // Gets filenames
  for(var filename in files) {  /// <<<<==== changed line
    final file = await File(filename);
    String contents = await file.readAsString();
    User user = User.fromJson(json.decode(contents));
    String name = user.NameLast + ", " + user.NameFirst;
    print(name);
    l.add(name);
  }
  return l;
}
_

すべてのファイル名が処理されるまで、関数は戻りません。

_files.forEach((filename) async {
_

つまり、コールバック内でawaitを使用できますが、forEachは_(filename) async {...}_が何を返すかを気にしません。

22

list.map(f)の使用に関するGünterのコメントを拡張するために、forEach呼び出しを正しく機能するように変換する例を次に示します。

壊れた例

forEachが先物を待つと誤って想定しています:

_Future<void> brokenExample(List<String> someInput) async {    
  List<String> results;

  someInput.forEach((input) async {
    String result = await doSomethingAsync(input);
    results.add(result);
  });

  return results;
}
_

修正された例

_Future.wait_および.map()を使用して、非同期関数が完了するのを待ちます。

_Future<void> correctedExample(List<String> someInput) async {
  List<String> results;

  await Future.wait(someInput.map((input) async {
    String result = await doSomethingAsync(input);
    results.add(result);
  }));

  return results;
}
_
6
Duncan Jones

また可能

await Future.forEach(yourList, (T elem) async { ...async staff });
3
iLobanov