🚀

非同期処理管理におけるRiverpodのFutureProviderとStreamProviderの活用事例

に公開

ここから記事本文

【注意】本記事はChatGPTによって生成されました


1. 導入:テーマの概要や重要性

Flutterアプリケーション開発において、非同期処理はAPI通信やデータベースアクセス、リアルタイムデータの取得など、多くの場面で欠かせない要素となっています。非同期処理を適切に管理しないと、UIが固まる・データ更新の反映漏れ・エラー処理の漏れなど、ユーザー体験に悪影響を及ぼす恐れがあります。そこで、状態管理パッケージであるRiverpodのFutureProviderStreamProviderは、非同期処理を宣言的かつシンプルに扱う手助けをしてくれます。

FutureProviderは単発の非同期処理(例:HTTPリクエストのレスポンス取得)に適し、StreamProviderは連続的にデータが流れてくるケース(例:FirebaseのリアルタイムデータやWebSocket)に最適です。これらを活用することで、FlutterのUIは状態変化に応じて自動的に再構築され、非同期処理のロード中・成功・失敗の状態管理も非常に直感的に行えます。

本記事では、RiverpodのFutureProviderStreamProviderの基礎から実践的な使い方、具体的なコード例、さらに応用的な活用シーンまでを詳しく解説します。Flutterの非同期処理管理の効率化や品質向上を目指す開発者にとって、有益な内容となるでしょう。


2. 背景・基礎知識

Riverpodとは?

RiverpodはFlutter向けの状態管理パッケージで、Remi Rousselet氏が開発しました。従来のStatefulWidgetsetStateの組み合わせでは、状態が複雑化すると管理が困難になる問題を解決します。Riverpodはプロバイダーと呼ばれる抽象を使い、状態の宣言的管理と再利用性を高めています。

FutureProviderとStreamProviderの概要

Provider名 対象 返却型 用途例
FutureProvider 単発の非同期処理 AsyncValue APIの1回限りのレスポンス取得
StreamProvider 連続的な非同期データの取得 AsyncValue Firebase、WebSocketの監視

どちらもAsyncValue型の値を返し、loading(読み込み中)、data(成功)、error(失敗)の状態を簡単に扱えます。

用語解説

  • 非同期処理:処理の完了を待たずに次の処理を進めるプログラムの実行方法
  • Future:将来のある時点で結果が返ってくる非同期処理の完了を表す型
  • Stream:複数のデータを時間とともに逐次的に受け取るための非同期データの流れ
  • AsyncValue:Riverpodが提供する、非同期処理の状態(loading/data/error)を包む型

3. 本論:技術的な詳細や仕組み、手順

FutureProviderの仕組み

FutureProviderは、Futureを返す関数を登録し、Futureの状態変化をAsyncValueで管理します。UIではref.watch()で監視し、AsyncValue.when()メソッドで状態に応じたWidgetを返す設計が基本です。

final userProvider = FutureProvider<User>((ref) async {
  final response = await fetchUserFromAPI();
  return response;
});

StreamProviderの仕組み

StreamProviderは、Streamを返す関数を登録し、最新のデータをキャッシュしつつリアルタイムにUIを更新します。ref.watch()で監視し、AsyncValueで状態管理する点はFutureProviderと同様です。

final chatMessagesProvider = StreamProvider<List<Message>>((ref) {
  return chatRepository.getMessageStream();
});

アーキテクチャ上の位置づけ

  • データ層:API呼び出しやDBアクセスの非同期処理を行う関数をプロバイダーに登録
  • 状態層FutureProviderStreamProviderが非同期処理の状態を管理
  • UI層ref.watch()で非同期データの状態を監視し、状態に応じてWidgetを描画

4. 具体例・コード例

以下は、FutureProviderでGitHubのユーザー情報を取得し、StreamProviderでチャットメッセージをリアルタイムに表示するサンプルコードです。

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

// GitHubユーザー情報を取得するFutureProvider
final githubUserProvider = FutureProvider.family<Map<String, dynamic>, String>((ref, username) async {
  final response = await Uri.parse('https://api.github.com/users/$username').readAsString();
  return Map<String, dynamic>.from(jsonDecode(response));
});

// チャットメッセージのStreamProvider(ここでは疑似的なストリーム)
final chatMessagesProvider = StreamProvider<List<String>>((ref) {
  return Stream.periodic(Duration(seconds: 2), (count) => List.generate(count + 1, (i) => 'メッセージ $i')).take(10);
});

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) => MaterialApp(home: HomePage());
}

class HomePage extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final githubUserAsync = ref.watch(githubUserProvider('flutter'));
    final chatMessagesAsync = ref.watch(chatMessagesProvider);

    return Scaffold(
      appBar: AppBar(title: Text('Riverpod FutureProvider & StreamProvider')),
      body: Column(
        children: [
          // FutureProviderの結果表示
          githubUserAsync.when(
            data: (user) => ListTile(
              title: Text(user['login']),
              subtitle: Text(user['bio'] ?? 'No bio'),
              leading: CircleAvatar(
                backgroundImage: NetworkImage(user['avatar_url']),
              ),
            ),
            loading: () => CircularProgressIndicator(),
            error: (e, _) => Text('Error: $e'),
          ),
          Divider(),
          // StreamProviderの結果表示
          Expanded(
            child: chatMessagesAsync.when(
              data: (messages) => ListView.builder(
                itemCount: messages.length,
                itemBuilder: (_, i) => ListTile(title: Text(messages[i])),
              ),
              loading: () => Center(child: CircularProgressIndicator()),
              error: (e, _) => Center(child: Text('Error: $e')),
            ),
          ),
        ],
      ),
    );
  }
}

実行手順

  1. Flutterプロジェクトを作成(flutter create riverpod_async_sample
  2. flutter_riverpodをpubspec.yamlに追加
  3. 上記コードをmain.dartにコピー
  4. flutter runでアプリ起動

5. 応用・発展

複数の非同期Providerを組み合わせる

Riverpodは異なるProviderの値を組み合わせることが得意です。例えば、FutureProviderの結果を受けて、条件に応じて別のStreamProviderを切り替えることも可能です。

FirebaseやWebSocketとの連携

StreamProviderはFirebase Firestoreのリアルタイムデータ監視や、WebSocketの受信データ管理にも理想的。リアルタイムチャットや通知機能の実装が容易になります。

エラーハンドリングのカスタマイズ

AsyncValuewhenmaybeWhenを使い、UIにエラー内容をわかりやすく表示したり、リトライボタンを表示するなどUX向上も図れます。


6. まとめ・今後の展望

RiverpodのFutureProviderStreamProviderは、Flutterの非同期処理管理を非常にシンプルかつ強力にします。非同期処理の状態(ロード・成功・失

Discussion