1. Streamとは
Streamは、非同期データの連続的な流れを処理するためのオブジェクトです。Streamを使用すると、イベントやデータの連続的なシーケンスを非同期で処理できます。Dartでは、Streamクラスを使用してストリームを表現します。
Streamの基本的な使用方法
Streamは、リスナーを登録することでデータの受信を開始します。リスナーは、データがストリームに到達すると呼び出されます。
Dart
Stream<int> countStream(int max) async* {
  for (int i = 1; i <= max; i++) {
    yield i;
  }
}
void main() {
  Stream<int> stream = countStream(5);
  stream.listen((data) {
    print('Data received: $data');
  });
}重要なポイント
async*関数は、非同期ジェネレータ関数を作成します。yieldキーワードを使用して、ストリームにデータを追加します。listenメソッドを使用して、ストリームにリスナーを登録します。
2. Streamの種類
Dartには、Single-Subscription StreamとBroadcast Streamの2種類のStreamがあります。
Single-Subscription Stream
Single-Subscription Streamは、1つのリスナーしか持つことができません。通常のStreamは、このタイプです。
Dart
Stream<int> singleStream() async* {
  yield 1;
  yield 2;
  yield 3;
}
void main() {
  Stream<int> stream = singleStream();
  stream.listen((data) {
    print('Single stream data: $data');
  });
}Broadcast Stream
Broadcast Streamは、複数のリスナーを持つことができます。asBroadcastStreamメソッドを使用して、通常のStreamをBroadcast Streamに変換します。
Dart
Stream<int> broadcastStream() async* {
  yield 1;
  yield 2;
  yield 3;
}
void main() {
  Stream<int> stream = broadcastStream().asBroadcastStream();
  stream.listen((data) {
    print('Broadcast stream data (listener 1): $data');
  });
  stream.listen((data) {
    print('Broadcast stream data (listener 2): $data');
  });
}3. StreamController
StreamControllerを使用すると、手動でストリームにデータを追加できます。StreamControllerは、ストリームを生成し、データ、エラー、および完了イベントを制御します。
StreamControllerの使用
Dart
import 'dart:async';
void main() {
  final controller = StreamController<int>();
  controller.stream.listen((data) {
    print('StreamController data: $data');
  });
  controller.add(1);
  controller.add(2);
  controller.add(3);
  controller.close();
}重要なポイント
StreamControllerを使用してストリームを作成します。addメソッドを使用して、ストリームにデータを追加します。closeメソッドを使用して、ストリームを閉じます。
4. Streamの操作
Streamには、さまざまな操作を行うためのメソッドが用意されています。これには、フィルタリング、マッピング、結合などが含まれます。
フィルタリング
Dart
Stream<int> numberStream() async* {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
}
void main() {
  Stream<int> stream = numberStream();
  stream.where((number) => number % 2 == 0).listen((data) {
    print('Filtered data: $data');
  });
}マッピング
Dart
Stream<int> numberStream() async* {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
}
void main() {
  Stream<int> stream = numberStream();
  stream.map((number) => number * 2).listen((data) {
    print('Mapped data: $data');
  });
}5. イベントハンドリング
イベントハンドリングは、ユーザーの操作やシステムイベントに応じて適切な処理を行うための手法です。Dartでは、Streamを使用してイベントを処理することが一般的です。
ボタンのクリックイベントのハンドリング(Flutterの例)
Dart
import 'package:flutter/material.dart';
void main() {
  runApp(MyApp());
}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Event Handling Example')),
        body: Center(
          child: ClickCounter(),
        ),
      ),
    );
  }
}
class ClickCounter extends StatefulWidget {
  @override
  _ClickCounterState createState() => _ClickCounterState();
}
class _ClickCounterState extends State<ClickCounter> {
  int _count = 0;
  void _incrementCounter() {
    setState(() {
      _count++;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text('You have pressed the button this many times:'),
        Text(
          '$_count',
          style: Theme.of(context).textTheme.headline4,
        ),
        ElevatedButton(
          onPressed: _incrementCounter,
          child: Text('Increment Counter'),
        ),
      ],
    );
  }
}6. 例題
例題1: StreamControllerを使用したデータの追加
Dart
import 'dart:async';
void main() {
  final controller = StreamController<int>();
  controller.stream.listen((data) {
    print('StreamController data: $data');
  });
  for (int i = 1; i <= 5; i++) {
    controller.add(i);
  }
  controller.close();
}例題2: Streamの操作(フィルタリングとマッピング)
Dart
Stream<int> numberStream() async* {
  for (int i = 1; i <= 5; i++) {
    yield i;
  }
}
void main() {
  Stream<int> stream = numberStream();
  stream
      .where((number) => number % 2 == 0)
      .map((number) => number * 2)
      .listen((data) {
    print('Processed data: $data'); // Processed data: 4, Processed data: 8
  });
}例題3: 複数のリスナーを持つBroadcast Stream
Dart
Stream<int> broadcastStream() async* {
  for (int i = 1; i <= 5; i++) {
    yield i;
  }
}
void main() {
  Stream<int> stream = broadcastStream().asBroadcastStream();
  stream.listen((data) {
    print('Listener 1: $data');
  });
  stream.listen((data) {
    print('Listener 2: $data');
  });
}↓次回内容:
6-1. Dartの標準ライブラリ
Dartには豊富な標準ライブラリが用意されており、これらを使用することで、基本的な機能から高度な機能まで簡単に利用することができます。標準ライブラリには、コレクション、ファイルI/O、HTTPリクエスト、JSON操作などが含まれます。
6-1-1. 標準ライブラリのインポート
標準ライブラリを使用するには、importキーワードを使ってライブラリをインポートします。