Есть ли в Dart специальный тип Stream
Что проверяют
Понимаете ли вы асинхронную модель Dart: чем Stream отличается от Future и как поток событий живёт во Flutter-приложении. Следом почти всегда спрашивают про разницу между single-subscription и broadcast-стримом и о том, кто отвечает за отписку.
Как отвечать
Да, Stream<T> из dart:async это последовательность асинхронных событий: ноль или больше значений, возможные ошибки и сигнал завершения. Future<T> отдаёт один результат, Stream<T> сколько угодно.
- виды: single-subscription (по умолчанию) допускает одного слушателя и копит события, пока тот не подпишется. Так устроены чтение файла и HTTP-ответ. Broadcast (
StreamController.broadcast(),asBroadcastStream()) раздаёт события всем текущим слушателям и ничего не хранит для опоздавших; - создание:
StreamController, генераторыasync*сyield, фабрикиStream.fromIterable(),Stream.periodic(),Stream.fromFuture(); - потребление:
listen()возвращаетStreamSubscription, её можно поставить на паузу и отменить черезcancel(). В async-функции удобнееawait for; - преобразования:
map,where,asyncMap,distinct,expand, как у коллекций, только асинхронно; - ошибки: колбэк
onErrorвlisten(), флагcancelOnError,handleError()в цепочке.
Во Flutter стрим чаще всего попадает в StreamBuilder, а на стримах построены пакеты вроде bloc, где состояние отдаётся наружу потоком.
Ответственность разделена: кто создал StreamController, тот вызывает close(), а кто подписался, вызывает cancel(), во Flutter обычно в dispose().
Где спотыкаются
Подписываются на обычный стрим второй раз и получают StateError с текстом Stream has already been listened to. Нужен broadcast или отдельный стрим на каждого слушателя.
Путают close() и cancel(). Закрыть чужой стрим нельзя, а неотменённая подписка на долгоживущий стрим держит виджет в памяти после ухода с экрана.
Создают стрим прямо в build() и передают в StreamBuilder. На каждой перестройке появляется новый поток и новая подписка, а состояние сбрасывается. Стрим создают в initState() или берут из слоя состояния.