Рано или поздно в жизни каждого Flutter-разработчика появляется необходимость работать с потоками Stream. Официальная документация достаточно просто и доступно объясняет весь базовый функционал стримов. Но бывают кейсы, в которых его может быть не достаточно.
Например, вам нужно подключить подписчика StreamSubscription к широковещательному потоку и получить доступ к последнему событию, сгенерированному до момента подключения. Базовый функционал потоков в Dart не дает такой возможности, так как события не кэшируются, и подписчики получают доступ только к тем из них, которые были сгенерированы потоком после подписки.
Здесь на помощь придет библиотека rxdart. Разберемся с ее возможностями.
Подключение к проекту у библиотеки стандартное — достаточно добавить зависимость в pubspec.yaml.
1. Классы потоков
rxdart дает доступ к множеству дополнительных Stream-классов. Вот некоторые из них:
▫️TimerStream — выдает заданное значение только по окончании заданного промежутка времени
TimerStream('событие', Duration(minutes: 1))
.listen((i) => print(i)); // выводит 'событие' через 1 минуту
▫️MergeStream — объединяет события нескольких потоков в один
MergeStream([
TimerStream(1, Duration(days: 10)),
Stream.fromIterable([2])
])
.listen(print); // выводит 2, 1
▫️RangeStream — возвращает поток int-значений по указанному диапазону
RangeStream(1, 3).listen((i) => print(i)); // выводит 1, 2, 3
2. Расширения
Кроме классов библиотека дает возможность использовать у стандартных экземпляров Stream дополнительные функции с помощью расширений:
▫️delay() — делает задержку выдачи событий на заданный период Duration
Stream.fromIterable([1, 2, 3, 4])
.delay(Duration(seconds: 1))
.listen(print); // [через секунду] выводит 1, 2, 3, 4 одномоментно
▫️debounce() — при отсутствии заданного Duration паузы между событиями игнорирует их, дает доступ только к собятиям с паузами
Stream.fromIterable([1, 2, 3, 4])
.debounce((_) => TimerStream(true, Duration(seconds: 1)))
.listen(print); // выводит 4
▫️mapTo() — выдает константное значение каждый раз, когда поступает событие
Stream.fromIterable([1, 2, 3, 4])
.mapTo(true)
.listen(print); // выводит true, true, true, true
▫️takeLast() — пропускает только те события, которые были сгенерированы после получения какого-то конкретного значения
Stream.fromIterable([1, 2, 3, 4, 5])
.takeLast(3)
.listen(print); // выводит 3, 4, 5
3. Объекты Subjects
Subjects в rxdart — это те же стандартные объекты StreamController, но с дополнительными функциями. Всего их два:
▫️BehaviorSubject — контроллер, который кэширует последнее полученное значение. В момент подписки на поток, управляемый этим контроллером, подписчик получает первым то событие, которое было сгенерировано последним перед его подключением. Этот объект как раз прекрасно позволяет решить кейс, описанный в начале поста.
▫️ReplaySubject — тоже кеширует события, как и BehaviorSubject. Если вам необходимо сохранять не только последнее событие, а еще и другие, этот объект прекрасно справится с этой задачей.
4. Объект Observable
Observable — аналог Stream, в большинстве случаев работает идентично стандартным Stream. Но команда fluttercommunity.dev предупреждает, что в некоторых ситуациях поведение может сильно отличаться. С этими отличиями перед использованием стоит ознакомится в документации.
Делитесь в комментариях своим опытом использования rxdart и работы с потоками во Flutter-приложениях💬
