【Flutter】dartの非同期処理 forEachでawaitを待ってくれないときの対処法（エラー対処法）

# 前提： await と async
API通信などで非同期処理を実現する上で使用します。

* async: 非同期メソッドを定義する場合に使用する
* await: 非同期メソッドの実行を待ってから以降の処理をしたい場合に使用する

### 参考記事
下記にわかりやすく記載してくれてます
https://qiita.com/tanaka512/items/6a326b0d92667b3cac65

# やりたいこと
* ２つのAPIからデータを取得する

```
    final List<String> _requestSoundsUrls = [
      'assets/json/soundBox.json',
      'assets/json/audioList.json'
    ];
```

* 下記でAPIへリクエストし、UIの描画に使用するJson形式のデータを取得

```
await SoundsApiProvider().fetchSoundsApi(_requestSoundsUrls[i]);
```

* レスポンスのJsonをパースし、soundsListに格納

```
        List<Map<String, dynamic>> jsonAudioList =
            new List<Map<String, dynamic>>.from(jsonArray['audioList']);
        List<Sounds> soundsList =
            jsonAudioList.map((i) => new Sounds.fromJson(i)).toList();
        soundsLists.add(soundsList)
```

## 問題のコード1 ：List.forEach (非同期処理がうまく行かない)
このコード(error.dart)だとawaitしている下記のコードを待たずにコードが流れてしまい、UIでNULLエラーが返却される

```
await SoundsApiProvider().fetchSoundsApi(_requestSoundsUrls[i]);
```

```dart:error.dart
    final List<String> _requestSoundsUrls = [
      'assets/json/soundBox.json',
      'assets/json/audioList.json'
    ];

    List<List<Sounds>> soundsLists = List<List<Sounds>>();
    Future.forEach(_requestSoundsUrls, (url) async {
      final String _soundsResponse =
          await SoundsApiProvider().fetchSoundsApi(url);

      if (_soundsResponse != "") {
        Map jsonArray = json.decode(_soundsResponse);

        // http通信ではなくて、ローカルからファイル取得
        List<Map<String, dynamic>> jsonAudioList =
            new List<Map<String, dynamic>>.from(jsonArray['audioList']);

        List<Sounds> soundsList =
            jsonAudioList.map((i) => new Sounds.fromJson(i)).toList();
        soundsLists.add(soundsList);
      } else {
        throw Exception("ERROR");
      }
    });
```

## 問題のコード2 ：Future.forEach (非同期処理がうまく行かない)
こちらも結果は同じ

```dart:error.dart
    final List<String> _requestSoundsUrls = [
      'assets/json/soundBox.json',
      'assets/json/audioList.json'
    ];

    List<List<Sounds>> soundsLists = List<List<Sounds>>();
    _requestSoundsUrls.forEach((url) async {
      final String _soundsResponse =
          await SoundsApiProvider().fetchSoundsApi(url);

      if (_soundsResponse != "") {
        Map jsonArray = json.decode(_soundsResponse);

        // http通信ではなくて、ローカルからファイル取得
        List<Map<String, dynamic>> jsonAudioList =
            new List<Map<String, dynamic>>.from(jsonArray['audioList']);

        List<Sounds> soundsList =
            jsonAudioList.map((i) => new Sounds.fromJson(i)).toList();
        soundsLists.add(soundsList);
      } else {
        throw Exception("ERROR");
      }
    });

```


### 発生したエラー
RangeError (index): Invalid value: Valid value range is empty: 0

# 対処法
## 対処法1：　await Future.ForEach (うまくawaitされる）
Futureを返す、非同期メソッドはawaitが使える。
**awaitをつければ、中の処理が終わるのを待ってくれる** （優秀な先輩に教えてもらいました。ありがとうございます！）
ちなみに、**await List.ForEach**　は文法エラーになる。（⚠注意）

```dart:success1.dart
    final List<String> _requestSoundsUrls = [
      'assets/json/soundBox.json',
      'assets/json/audioList.json'
    ];

    List<List<Sounds>> soundsLists = List<List<Sounds>>();
    _requestSoundsUrls.forEach((url) async {
      final String _soundsResponse =
          await SoundsApiProvider().fetchSoundsApi(url);

      if (_soundsResponse != "") {
        Map jsonArray = json.decode(_soundsResponse);

        // http通信ではなくて、ローカルからファイル取得
        List<Map<String, dynamic>> jsonAudioList =
            new List<Map<String, dynamic>>.from(jsonArray['audioList']);

        List<Sounds> soundsList =
            jsonAudioList.map((i) => new Sounds.fromJson(i)).toList();
        soundsLists.add(soundsList);
      } else {
        throw Exception("ERROR");
      }
    });
```

## 対処法2：　for (うまくawaitされる）
単純なforで再起させたこのコード(success.dart)だと、ちゃんとawaitを待ってくれるようになり、NULLエラーが解消された

```dart:success2.dart
    final List<String> _requestSoundsUrls = [
      'assets/json/soundBox.json',
      'assets/json/audioList.json'
    ];

    List<List<Sounds>> soundsLists = List<List<Sounds>>();
    for(int i = 0; i < _requestSoundsUrls.length; i++){
      final String _soundsResponse =
          await SoundsApiProvider().fetchSoundsApi(_requestSoundsUrls[i]);

      if (_soundsResponse != "") {
        Map jsonArray = json.decode(_soundsResponse);

        // http通信ではなくて、ローカルからファイル取得
        List<Map<String, dynamic>> jsonAudioList =
            new List<Map<String, dynamic>>.from(jsonArray['audioList']);

        List<Sounds> soundsList =
            jsonAudioList.map((i) => new Sounds.fromJson(i)).toList();
        soundsLists.add(soundsList);
      } else {
        throw Exception("ERROR");
      }
    }
```