Irbisa · Cheatsheet
Streams & Rx
Streams, StreamController, StreamBuilder, broadcast streams
What is the difference between a
Futureand aStream, and when do you use each?What is a
Streamin Dart, and how do single-subscription and broadcast streams differ?// Single-subscription: exactly one listenerfinal single = StreamController<int>();single.stream.listen((v) => print('A got $v'));// single.stream.listen(...); // Bad state: Stream has already been listened to // Broadcast: many listeners, no replay…What does this code print, and what changes if you remove
.broadcast()?import 'dart:async'; Future<void> main() async { final controller = StreamController<String>.broadcast(); controller.add('hello'); controller.stream.listen(print); controller.add('world'); await controller.close();}What is the difference between
FutureBuilderandStreamBuilder?class _ProfileState extends State<Profile> { late final Future<User> _user = api.fetchUser(widget.id); // once late final Stream<int> _unread = chat.watchUnread(widget.id); // over time @override Widget build(BuildContext context) {…What does a
StreamControllergive you, and how do you use it to turn a callback API (a sensor, a socket) into aStream?Stream<int> watch(ValueListenable<int> source) { late final StreamController<int> controller; void push() => controller.add(source.value); controller = StreamController<int>.broadcast( onListen: () => source.addListener(push), // first listener: start…What is a
StreamSubscription, and how do you manage its lifecycle in a widget?class _TickerState extends State<Ticker> { StreamSubscription<int>? _sub; int _last = 0; @override void initState() {…When do you use
await forinstead oflistenon a stream?// Sequential: the next order is not delivered until this one is savedFuture<void> saveAll(Stream<Order> orders) async { await for (final order in orders) { await db.insert(order); if (order.isLast) break; // cancels the subscription }…What does this code print, and in what order?
Stream<int> numbers() async* { print('start'); yield 1; yield 2;} void main() { final stream = numbers(); print('created'); stream.listen(print); print('listened');}What does
StreamBuilderdo for you, and what doconnectionStateand the snapshot tell you?class _PricesState extends State<Prices> { late final Stream<Quote> _quotes = repo.watchQuotes(widget.symbol); @override Widget build(BuildContext context) { return StreamBuilder<Quote>(…Two widgets listen to the same stream and you get "Bad state: Stream has already been listened to". What is happening?
// wrong: two listeners on a single-subscription streamfinal controller = StreamController<int>();controller.stream.listen(print);controller.stream.listen(print); // Bad state: already listened to// right: broadcast when you own the controllerfinal broadcast = StreamController<int>.broadcast();…How do errors travel through a
Stream, and what happens to an error nobody handles?// wrong: data handled, errors escape to the zone and the crash reporter_sub = repo.messages.listen((m) => setState(() => _messages.add(m))); // right: handle both channels_sub = repo.messages.listen( (m) => setState(() => _messages.add(m)),…Find the bug: the progress bar reaches 100%, but the "Upload complete" message never appears.
Stream<double> upload(Uploader client, File file) { final progress = StreamController<double>(); client .send(file, onProgress: (sent, total) => progress.add(sent / total)) .catchError((Object e, StackTrace s) => progress.addError(e, s)); return progress.stream;} Future<void> finish(Uploader client, File file) async { await for (final p in upload(client, file)) { setProgress(p); } showDone();}What is a
StreamTransformer, and how do you write your own stream operator without rxdart?// Per event: trim lines and drop blank onesfinal trimNonEmpty = StreamTransformer<String, String>.fromHandlers( handleData: (line, sink) { final t = line.trim(); if (t.isNotEmpty) sink.add(t); },…How do you combine several streams:
merge,zip,combineLatest?import 'package:rxdart/rxdart.dart'; // merge: every event from every source, in arrival orderfinal allMessages = Rx.merge<Message>([channelA.messages, channelB.messages]); // zip: the i-th question with the i-th answer…What does rxdart add on top of
dart:async(BehaviorSubject,debounceTime,switchMap)?import 'package:rxdart/rxdart.dart'; class SearchViewModel { SearchViewModel(this._api); final SearchApi _api;…Your repository re-emits an identical list on every poll and the page rebuilds each time; you added
distinct()and nothing changed: why?You call
await feed.quotes.firstto read the current price and the call never returns: what did you assume that aStreamdoes not provide?Sign-in success shows its
SnackBarthree times because it is fired inside thebuilderof aStreamBuilder: what rule is being broken?// wrong: runs on every rebuild, not on every eventbuilder: (context, snap) { if (snap.data is SignedIn) { ScaffoldMessenger.of(context).showSnackBar(welcome); } return const HomeBody();…Find the bug: after switching between chats, messages from the chat you left keep appearing in the open one.
class ChatController { ChatController(this._repo); final ChatRepository _repo; final messages = ValueNotifier<List<Message>>(const []); StreamSubscription<Message>? _sub; void open(String chatId) { messages.value = const []; _sub = _repo .watch(chatId) .listen((m) => messages.value = [...messages.value, m]); } void dispose() { _sub?.cancel(); messages.dispose(); }}How are streams used for state management in Flutter, and why do apps rarely keep state in a raw
StreamController?What is backpressure, and how do single-subscription and broadcast streams handle it?
// A producer that respects backpressure: suspends at yield while pausedStream<List<int>> readChunks(File file) async* { final raf = await file.open(); try { while (true) { final chunk = await raf.read(64 * 1024);…A WebSocket price feed goes quiet on a flaky mobile network, the stream never errors, and the UI shows a stale price forever: what do you add?
class PriceFeed { final _out = StreamController<Quote>.broadcast(); IOWebSocketChannel? _channel; StreamSubscription<Quote>? _sub; Timer? _retry; int _attempt = 0;…A test adds an event to a
StreamController, asserts on the listener immediately, and nothing has run yet: issync: truethe fix?// wrong: the assertion runs before the listener doestest('stores the value', () { final controller = StreamController<int>(); var seen = 0; controller.stream.listen((v) => seen = v); controller.add(7);…