← Назад к вопросам

Для чего нужны Stream?

1.0 Junior🔥 261 комментариев
#Dart#Асинхронность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Для чего нужны Stream?

Stream — это один из самых мощных и фундаментальных инструментов в Dart и Flutter для асинхронной обработки данных. Это абстракция, которая позволяет работать с последовательностями событий, поступающих во времени.

Основное назначение Stream

Stream предоставляет способ обработки асинхронных последовательностей данных. Вместо того чтобы получить результат сразу, вы подписываетесь на Stream и получаете значения по мере их появления. Это особенно полезно когда:

  • Данные поступают асинхронно — с сервера, из файлов, с датчиков
  • Нужно реагировать на изменения — обновление состояния в реальном времени
  • Обработка множественных событий — клики пользователя, сообщения, уведомления
  • Работа с веб-сокетами — live-данные, chat-приложения

Основные типы Stream

Single-subscription Stream — может иметь только одного слушателя:

Stream<int> numbersStream = Stream<int>.periodic(
  Duration(seconds: 1),
  (count) => count,
).take(5);

var subscription = numbersStream.listen((value) {
  print("Значение: $value");
});

Broadcast Stream — может иметь множество слушателей одновременно:

Stream<int> broadcastStream = numbersStream.asBroadcastStream();

var subscription1 = broadcastStream.listen((value) {
  print("Слушатель 1: $value");
});

var subscription2 = broadcastStream.listen((value) {
  print("Слушатель 2: $value");
});

Практическое применение во Flutter

1. Работа с BLoC паттерном

Stream используются в BLoC (Business Logic Component) для управления состоянием:

class CounterBloc {
  final _counterController = StreamController<int>();
  
  Stream<int> get counterStream => _counterController.stream;
  
  void increment() {
    _counter++;
    _counterController.sink.add(_counter);
  }
  
  void dispose() {
    _counterController.close();
  }
}

2. StreamBuilder для обновления UI

StreamBuilder<int>(
  stream: bloc.counterStream,
  initialData: 0,
  builder: (context, snapshot) {
    if (snapshot.hasError) {
      return Text("Ошибка: ${snapshot.error}");
    }
    return Text("Значение: ${snapshot.data}");
  },
)

3. Работа с API данными

Stream<List<User>> fetchUsersStream() async* {
  final response = await http.get(Uri.parse(apiUrl));
  if (response.statusCode == 200) {
    List<User> users = parseUsers(response.body);
    yield users;
  } else {
    throw Exception("Ошибка загрузки");
  }
}

Трансформация Stream

Stream можно преобразовывать с помощью операторов:

stream
  .map((value) => value * 2)  // преобразование
  .where((value) => value > 5)  // фильтрация
  .distinct()  // удаление дубликатов
  .debounce(Duration(milliseconds: 300))  // задержка
  .listen((value) => print(value));

Важные правила работы со Stream

  • Всегда отписывайтесь — вызывайте cancel() на subscription в dispose(), иначе будут утечки памяти
  • Обрабатывайте ошибки — используйте параметр onError в listen() или catchError()
  • Используйте StreamBuilder — он автоматически управляет подпиской в Flutter
  • Выбирайте правильный тип — Single-subscription для простых случаев, broadcast для множественных слушателей

Stream — это необходимый инструмент для построения асинхронных, реактивных приложений на Flutter.