StreamProvider
StreamProvider は FutureProvider の Stream 版です。
一般的には次のような用途で使われます。
- Firebase や WebSocket の監視するため。
- 一定時間ごとに別のプロバイダを更新するため。
Stream 自体が値の更新を監視する性質を持つため、StreamProvider を使うことにあまり意義を見出せない方もいるかもしれません。
Flutter の StreamBuilder で十分ではないか、と。
しかし、StreamBuilder の代わりに StreamProvider を使うことで次の利点を得ることができます。
- 他のプロバイダで ref.watch を通じてストリームを監視することができる。
- AsyncValue により loading/error のステートを適切に処理することができる。
- 通常のストリームとブロードキャスト(broadcast)ストリームを区別する必要がない。
- ストリームから出力された直近の値をキャッシュしてくれる(途中で監視を開始しても最新の値を取得することができる)。
- StreamProviderをオーバーライドすることでテスト時のストリームを簡単にモックすることができる。
使用例: ソケットを使ったライブチャット
StreamProviderは、ビデオストリーミングや天気予報のAPIなど非同期データのストリームを扱うときに使用されます。
final chatProvider = StreamProvider<List<String>>((ref) async* {
  // Connect to an API using sockets, and decode the output
  final socket = await Socket.connect('my-api', 4242);
  ref.onDispose(socket.close);
  
  var allMessages = const <String>[];
  await for (final message in socket.map(utf8.decode)) {
    // A new message has been received. Let's add it to the list of all messages.
    allMessages = [...allMessages, message];
    yield allMessages;
  }
});
そして、UIはこのようにライブストリーミングチャットを監視することができます:
Widget build(BuildContext context, WidgetRef ref) {
  final liveChats = ref.watch(chatProvider);
  // Like FutureProvider, it is possible to handle loading/error states using AsyncValue.when
  return switch (liveChats) {
    // Display all the messages in a scrollable list view.
    AsyncData(:final value) => ListView.builder(
        // Show messages from bottom to top
        reverse: true,
        itemCount: value.length,
        itemBuilder: (context, index) {
          final message = value[index];
          return Text(message);
        },
      ),
    AsyncError(:final error) => Text(error.toString()),
    _ => const CircularProgressIndicator(),
  };
}