🙆

[Flutter]FutureProviderとStreamProviderの個人的まとめ

2022/09/04に公開

注意:公式を見るのが一番ですのでそちらも見てください!
公式記事
参考記事
参考記事

FutureProvider

FutureProviderとは

  • 「単一のデータ取得」において、「非同期操作」が可能な Provider

である。
( 「断続的に」ではなく、「一回限り」 で非同期にデータを更新する)

使い所

  • 非同期操作を実行し、そのデータを返り値にするとき
  • 非同期操作の error/loading ステートを適切に処理するとき。
  • 非同期的に取得した複数の値を組み合わせて一つの値にするとき。

sample code(+Points)

ボタンを押下すると3秒後に「Hello World」を取得する簡単なアプリ

main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  // ①ProviderScopeでラップする
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'FutureProvider',
      theme: ThemeData(
        textTheme: const TextTheme(bodyText2: TextStyle(fontSize: 50)),
      ),
      home: HomePage(),
    );
  }
}

// ②FutureProviderの作成 (単一のデータを非同期で取得する)
final futureProvider = FutureProvider<dynamic>((ref) async {
  await Future.delayed(const Duration(seconds: 3));
  return 'Hello World';
});

// ③FutureProviderを作成すると「AsyncValue」オブジェクトを生成できる
//「AsyncValue」は非同期通信の通信中、通信終了、異常終了処理をハンドリングしてくれるRiverpodの便利な機能のこと

class HomePage extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    // ③AsyncValueオブジェクトを取得する
    final asyncValue = ref.watch(futureProvider);
    return Scaffold(
      appBar: AppBar(title: const Text('Hallo World')),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.refresh),
        onPressed: () {
          // ④押下すると状態を更新する処理
          ref.refresh(futureProvider);
        },
      ),
      body: Center(
        child: asyncValue.when(//⑤ AsyncValueの状態別に返り値を分岐指定する。
          error: (err, _) => Text(err.toString()), //エラー時 => エラー文を出力
          loading: () => const CircularProgressIndicator(), //読み込み時 => インジケータを表示
          data: (data) => Text(data.toString()), //データ受け取り時 => データをString変換して表示
        ),
      ),
    );
  }
}

Points

  • ①:ProviderScopeでルート(一番原始の)widgetをラップ
    これにより変更を追える
  • ②:FutureProviderの定義。(設置。単一のデータを非同期で取得する)
    futureProvider の中に、非同期で取得したい単一データを格納するようにした。
  • ③:FutureProviderを作成すると「AsyncValue」オブジェクトを(returnとして)生成できる。非同期通信の通信中、通信終了、異常終了処理をハンドリングしてくれるRiverpodの便利な機能。
    ref.watch(引数)で(引数)の部分を監視(リッスン)して、変更があれば FutureProvider を監視した際の戻り値として返す。
  • ④:この ref.refresh(futureProvider) メソッドにより(futureProvider の中の) StateController オブジェクトは再度生成される状態を更新することになる。ボタンを押下することにより、オブジェクトを再生成し、状態更新するようにしている。
  • ⑤:非同期処理ではAsyncValueを使用してローディング中またはエラーが発生した場合の値も返す必要があり、先ほど定義したfutureにwhenを使用してAsyncValueの状態別にコールバック関数で戻り値を指定する。

StreamProvider

StreamProviderとは

  • 「断続的なデータ取得」において、「非同期操作」が可能な Provider

である。

sample code(+Points)

main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

void main() {
  // ProviderScopeでラップする
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Count Down',
      theme: ThemeData(
        textTheme: const TextTheme(bodyText2: TextStyle(fontSize: 50)),
      ),
      home: HomePage(),
    );
  }
}

// StreamProviderの作成 (データを非同期で断続的に取得する)
final streamProvider = StreamProvider<dynamic>((ref) {
  Stream<dynamic> getNumbers() async* {
    await Future.delayed(const Duration(seconds: 1));
    yield 'Are You Ready?';

    await Future.delayed(const Duration(seconds: 1));
    yield 3;

    await Future.delayed(const Duration(seconds: 1));
    yield 2;

    await Future.delayed(const Duration(seconds: 1));
    yield 1;

    await Future.delayed(const Duration(seconds: 1));
    yield '';
  }

  return getNumbers();
});

// StreamProviderを作成すると「AsyncValue」オブジェクトを生成できる
//「AsyncValue」は非同期通信の通信中、通信終了、異常終了処理をハンドリングしてくれるRiverpodの便利な機能のこと

class HomePage extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    // AsyncValueオブジェクトを取得する
    final asyncValue = ref.watch(streamProvider);
    return Scaffold(
      appBar: AppBar(title: const Text('Count Down')),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.refresh),
        onPressed: () {
          // 状態を更新する
          ref.refresh(streamProvider);
        },
      ),
      body: Center(
        child: asyncValue.when(
          error: (err, _) => Text(err.toString()), //エラー時
          loading: () => const CircularProgressIndicator(), //読み込み時
          data: (data) => Text(data.toString()), //データ受け取り時
        ),
      ),
    );
  

Points

  • final streamProvider = StreamProviderでStreamBuilderを定義。

FutureProviderr と StreamProviderの違い

  • FutureProvider:「単一のデータ取得」に使う
  • StreamProvider:「断続的なデータ取得」に使う

まあFutureとStreamの違いも単一の変数を扱うとき・Listみたいに複数データを扱うときって違いだから、この違いも普通な感じもする。
次はFutureとStreamの違いについて調べよ〜



まだまだ全然理解していないですが、今回は以上です。間違えが見つかり次第、或いは知識がアップデートされ次第改訂していきます。🙏

GitHubで編集を提案

Discussion