Streams – это потоки данных, испускаемых последовательно в количестве от 0 до n. Если проводить аналогии с RxJava, то это Stream работает как Observable. Это чистая реактивщина, которая присутствует в Dart из коробки.
Для того, чтобы получать данные из потока Stream, нужно подписаться на него.
final
_stream = SomeGenerator().stream;
final subscription = _stream.listen(
(data) => print(‘$data’),
);
Важный момент: По умолчанию на Stream может подписаться только один слушатель. Чтобы один Stream могли слушать несколько подписчиков, нужно вызвать на stream-е метод asBroadсastStream
Также можно слушать на ошибки, а также есть очень удобный флаг cancelOnError, который позволяет приложению не падать в случае ошибки в потоке. Что очень удобно, и не надо писать onErrorReturn как в RxJava.
final subscription = _stream.listen(
data) => print(‘$data’),
),
onError:(err) {
print(‘err’)
},
cancelOnError: false,
onDone:() {
print(‘Done)
}
);
также, как и в Rx, у Stream-ов есть оператор map, который позволяет фильтровать испускаемые элементы:
final subscription = _ SomeGenerator().stream
.where((data) => data.isValid() == true)
.map((data) => ‘Valid $data’)
.listen(
(data) => print(‘$data’),
);
StreamController
Для того, чтобы создать Stream вручную, нужно использовать класс StreamController. Это обертка над потоком Stream, которая позволяет отправлять данные в поток. Посмотрим исходник класса. В нем все достаточно просто. Stream c дженерик-типом и колбеки onListen, onPause, onResume, onCancel:
abstract class StreamController<T> implements StreamSink<T> {
/** The stream that this controller is controlling. */
Stream<T> get stream;
. . .
/**
* The callback which is called when the stream is listened to.
*
* May be set to `null`, in which case no callback will happen.
*/
ControllerCallback get onListen;
void set onListen(void onListenHandler());
/**
* The callback which is called when the stream is paused.
*
* May be set to `null`, in which case no callback will happen.
*
* Pause related callbacks are not supported on broadcast stream controllers.
*/
ControllerCallback get onPause;
void set onPause(void onPauseHandler());
/**
* The callback which is called when the stream is resumed.
*
* May be set to `null`, in which case no callback will happen.
*
* Pause related callbacks are not supported on broadcast stream controllers.
*/
ControllerCallback get onResume;
void set onResume(void onResumeHandler());
Для того, чтобы отослать событие/данные в поток Stream, нужно на StreamController-е вызвать метод sink.add(<данные>). Как это работает на практике мы увидим дальше в примере со счетчиком, а сейчас отметим важный момент как использовать Stream в UI.
Чтобы UI, то есть виджет мог обновляются в соответсвии с изменениями, поступающими от потока Stream, этот виджет нужно обернуть в специальный виджет StreamBuilder. Этот виджет имеет параметр stream, в котором мы указываем поток с данными, а также функцию билдера, в котором, используя получаемые от потока данные, можно отрисовывать виджет.
StreamBuilder(
stream: _myStream,
initialData: <объект>,
builder: (BuildContext context, AsyncSnapshot<Тип данных> snapshot) {
eturn Text('${snapshot.объект}');
},
),
Эта статья — из книги Быстрый старт Flutter-разработчика