2
0

More than 1 year has passed since last update.

【Flutter】Dartの非同期処理(Future・then)

Posted at

はじめに

Flutterでアプリ開発を行うには、Dart言語の使い方を理解しておく必要があります。今回は、Dart言語の非同期処理について説明します。非同期処理は、WebAPIを叩いたり、DBやファイルの読み書き等、時間のかかる処理を行う際に使用します。

動作環境

Flutterで新規プロジェクトを作成し、以下のここに処理を書いていくと書かれた2箇所に追加でコードを記述して動作確認していきます。画面にボタンを表示する単純なプログラムです。

import 'dart:io';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

+ // ここに処理を書いていく

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Hello World")),
        body: Center(
          child: ElevatedButton(
            child: Text("ボタン"),
            onPressed: () {
+             // ここに処理を書いていく
            },
          )
        ),
      ),
    );
  }
}

以下のような画面が表示されます。

Flutterの非同期処理

Flutterの非同期処理は、以下の2つの方法があります。今回は、理解が難しいFuture・thenを使用する方法を説明します。

  • Future・thenを使用する方法
  • async・awaitを使用する方法

非同期処理とは

まず、非同期処理とは何か、以下のプログラムを示します。プログラムを実行して、画面に表示されるボタンをクリックしてください。

import 'dart:io';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

   // ここに処理を書いていく
+  void task1() {
+   print("task1");
+  }
+
+  void task2() {
+   // 3秒待つ処理の後にprintを実行
+   sleep(Duration(seconds: 3));
+   print("task2: 3秒経ちました");
+  }
+
+  void task3() {
+   print("task3");
+  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Hello World")),
        body: Center(
          child: ElevatedButton(
            child: Text("ボタン"),
            onPressed: () {
              // ここに処理を書いていく
+             task1();
+             task2();
+             task3();
            },
          )
        ),
      ),
    );
  }
}

出力結果は以下の通りになります。

flutter: task1
flutter: task2: 3秒経ちました
flutter: task3
  • task1出力→3秒後→task2出力→task3出力となります
  • このように、順に処理を実行することを同期処理と言います
  • 時間のかかる処理の完了を待つと、次の処理が止まってしまいます。時間のかかる処理は非同期処理で実装します
  • 非同期処理は、処理の完了を待つ事なく次の処理を実行(並列に処理)します

上のプログラムで、時間のかかる部分を非同期処理に変更してみます。

import 'dart:io';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

   // ここに処理を書いていく
   void task1() {
     print("task1");
   }

   void task2() {
     sleep(Duration(seconds: 3));
   }

   void task3() {
     print("task3");
   }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Hello World")),
        body: Center(
          child: ElevatedButton(
            child: Text("ボタン"),
            onPressed: () {
              // ここに処理を書いていく
              task1();
+             Future(() {
+               task2();
+             },).then((value) {
+               print("task2: 3秒経ちました");
+             },);
              task3();
            },
          )
        ),
      ),
    );
  }
}

出力結果は以下の通りになります。

flutter: task1
flutter: task3
flutter: task2: 3秒経ちました
  • task1出力→task3出力→3秒後→task2出力となります
  • task2の終了を待つ事なく、task3を実行しています
  • Futureにより、時間がかかる部分を非同期処理で実装できました

それでは、以降で非同期処理の詳細について説明します。

非同期処理の詳細

Future とは

  • Futureは、非同期処理の実行完了後の未来において、実行結果を格納するための箱のようなものです。
  • Futureは複数の状態を持ちます
    • 非同期処理が未完了の状態
    • 非同期処理が完了の状態(実行結果を格納している)

Futureの処理の流れ

Futureの上記の2つの状態を、以下のプログラムで具体的に見てみましょう。

import 'dart:io';

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

   // ここに処理を書いていく

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Hello World")),
        body: Center(
          child: ElevatedButton(
            child: Text("ボタン"),
            onPressed: () {
              // ここに処理を書いていく
+              var myFuture = Future(() {
+                sleep(Duration(seconds: 5));
+                return 0;
+              }).then((value) {
+                print("完了");
+               print(value);
+              });
+              print("未完了");
+              print(myFuture);

            },
          )
        ),
      ),
    );
  }
}

出力結果は以下の通りになります。

flutter: 未完了
flutter: Instance of 'Future<Null>'
flutter: 完了
flutter: 0
  • Future内は非同期処理のため、Future後の処理が先に出力されています
  • 非同期処理が未完了の状態では、Futureの返り値(myFuture変数)はNullとなっています。処理が完了すると、returnの値である0が格納されています

Future・thenの書き方

次に、先ほどのプログラムを詳しく見てみましょう。

var myFuture = Future(() {
  sleep(Duration(seconds: 5));
  return 0;
}).then((value) {
  print("完了");
  print(value);
});
print("未完了");
print(myFuture);

Futureを使用した非同期処理は以下のように記述します。

Future((){ 
  // 時間のかかる処理
});

また、Futureの実行結果(返り値)を得るには以下のようにします。

var myFuture = Future(() {
  // 時間のかかる処理
  return 返り値
}).then((value) {
  // returnされた返り値がvalueに格納され、then以下が実行される
  print(value);
});
  • myFuture、return、thenを追加しています
  • returnの後(非同期処理終了後)、返り値がvalueに格納され、then以下が実行されます

Futureの実用例

これまで、Futureを自分自身で作って非同期処理を行いました。しかし、Flutterにおける非同期処理では、Futureを自分自身で作ることはほとんどありません。非同期処理のライブラリはFutureを考慮して作成されているためです。

実際に、一般的な非同期処理を試してみましょう。HTTP通信を行ってみます。まず、HTTP通信に必要なライブラリをインストールします。

flutter pub add dio

HTTP通信で、Web APIを叩いてみようと思います。今回使用するWeb APIは、httpbinです。登録など一切不要で、Web APIを使用した動作確認を行いたいときに手軽に使う事ができます。

以下のプログラムを実行してみましょう。httpbinを叩き、ipアドレスを取得して出力します。
※うまく動作しない場合は、実機でデバッグするようにしてください。

import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

   // ここに処理を書いていく
   
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Hello World")),
        body: Center(
          child: ElevatedButton(
            child: Text("ボタン"),
            onPressed: () {
              // ここに処理を書いていく
+             var dio = Dio();
+             var response = dio.get("http://httpbin.org/ip");
+             print(response);
+             response.then((value) {
+               print(value.data);
+             });
            },
          )
        ),
      ),
    );
  }
}

出力結果は以下の通りになります。

{origin: xx.xx.xx.xx}

では、プログラムを解説します。

var dio = Dio();
// 時間のかかる処理(HTTP通信)
// responseはFuture型のため、非同期処理が終わった後(thenの後)で値を取り出す
var response = dio.get("http://httpbin.org/ip");
// まだHTTP通信の結果は格納されていない
print(response);
response.then((value) {
  // HTTP通信の結果が格納されている
  print(value.data);
});
  • 時間のかかるHTTP通信はFutureの中で非同期処理しています
  • 非同期処理終了後、thenの中の処理を実行し、値を取り出します

非同期処理の典型例であるHTTP通信を試してみました。返り値のFutureのみthenを使って処理する事で、値を取得する事ができます。様々なライブラリをFuture・thenを使って試してみて下さい。

おわりに

Flutterの非同期処理(Future・thenを使用した方法)を説明しました。Futureの詳しい解説は、以下の動画がわかりやすいです。是非、動画を見てFutureについて理解を深めてみてください。

2
0
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
0