Flutter/Dart

【Flutter/Dart】FutureBuilder – 非同期で作るWidget

asoacasio

FutureBuilderとは、非同期処理の結果に基づいて、適切なWidgetを表示する機能です。

効果的に利用されるシナリオ

データを非同期にフェッチして画面を更新する場合

例えば、天気APIからデータを取得して、現在の天気を表示するWidgetを作るとします。

フェッチ処理は非同期に行われ、その結果を元に画面を作ります。

重い計算を行う場合

例えば、大量のデータに対して、複雑な計算を行い、その結果を表示するWidgetを作るとします。

重い計算処理は非同期に行われ、その結果を元に画面を作ります。

UI操作の結果を待って画面を更新する場合

例えば、ユーザに質問して、その答えがYESかNOかで異なる表示をするWidgetを作るとします。

ユーザの入力結果を非同期で待ち、その結果を基に画面を切り替えます。

メリット

非同期操作によるWidget表示を大幅にシンプルに実装できます。

  • 非同期操作を行いながらUIの状態を管理することができます。結果を待つ間にUIを更新する作業にも利用できます。
  • コードは直感的で可読性が高いです。
  • Futureの3つの状態(waiting / completed / error)がハンドリングできます。

サンプルコード

非同期にデータを取得し、そのデータをリスト形式で表示するページを作ります。

  • 非同期処理が完了するまではローディングを表示します。
  • エラーは50%の確率で返されます。
  • エラーを投げずに非同期処理が成功した場合は、0から4までのランダムな長さで作成されるリストが返されます。この結果によって画面を表示します。
import 'dart:math';

import 'package:flutter/material.dart';

class FutureBuilderPage extends StatefulWidget {
  const FutureBuilderPage({Key? key}) : super(key: key);

  @override
  _FutureBuilderPageState createState() => _FutureBuilderPageState();
}

class _FutureBuilderPageState extends State<FutureBuilderPage> {
  Future<List<String>> _fetchDataList() async {
    await Future.delayed(const Duration(seconds: 2));

    // データ生成のサンプルとして、ランダムな文字列のリストを生成する
    List<String> dataList =
        List<String>.generate(Random().nextInt(5), (index) => "Item $index");

    if (Random().nextBool()) {
      // 50% の確率でエラーをスロー
      throw Exception('Failed to load data');
    }
    return dataList;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('FutureBuilder'),
      ),
      body: Center(
        child: FutureBuilder<List<String>>(
          future: _fetchDataList(),
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.waiting:
                // 非同期処理中はローディング表示
                return const CircularProgressIndicator();
              case ConnectionState.done:
                // 非同期処理完了時
                if (snapshot.hasError) {
                  // エラー発生時
                  return Text('Error: ${snapshot.error}');
                } else {
                  // List形式のデータをListViewで表示
                  return ListView.builder(
                      itemCount: snapshot.data.length,
                      itemBuilder: (context, index) {
                        return ListTile(
                          title: Text('Loaded: ${snapshot.data[index]}'),
                        );
                      });
                }
              case ConnectionState.none:
                // 非同期処理が未実行の場合
                return const Text('Start the Future');
              default:
                // 予測不可能な状況用の表示
                return const Text('Something unexpected happened');
            }
          },
        ),
      ),
    );
  }
}

AsyncSnapshotは非同期操作から得られるデータまたはエラー情報が格納されています。

未完了か完了か、エラーか否かの情報が取得できます。

AsyncSnapshotから得た情報として

  • ConnectionState.none(未実行)
  • ConnectionState.waiting(処理中)
  • ConnectionState.done(完了後)

これらの状態に合わせて画面表示を変えています。

また、ConnectionState.done(完了後)では成功時とエラー時で画面を変えています。

更に、成功時の場合は、非同期処理の結果に合わせて画面表示を変えています。

このような状態に合わせて、適切に画面表示できるのがFutureBuilderとなります。

ABOUT ME
なっとう
なっとう
Fluttter開発 プログラマー
噛み砕いて説明できるようになれば、プログラマーとしての質が上がるのではないかと思い、ブログを始めました。 このノウハウが誰かのお役に立てば嬉しいです。
記事URLをコピーしました