LoginSignup
2
1

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-04-06

前提: await と async

API通信などで非同期処理を実現する上で使用します。

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

参考記事

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

やりたいこと

  • 2つの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]);
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 (非同期処理がうまく行かない)

こちらも結果は同じ

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 は文法エラーになる。(⚠注意)

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エラーが解消された

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");
      }
    }
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1