Dart streams
Skill almasumdev/awesome-flutter-agent-skills/.github/skills/concurrency_and_networking/dart-streams
Curated agent skills, conventions, and workflows for building Flutter apps with AI coding agents.
npx -y skills add almasumdev/awesome-flutter-agent-skills --skill dart-streamsAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Best practices for Dart Streams, StreamController, subscriptions, and combining streams with rxdart. Use this when implementing reactive data flows or subscribing to events.
SKILL.md
3.1 KB, as published. Nobody here has run it
Dart Streams Best Practices
Instructions
Streams represent sequences of async events. Use them for reactive data (DB change feeds, websockets, user input events) — not for one-shot results (use Future).
1. Single vs Broadcast
- Single-subscription (default): exactly one listener. Good for request/response-style sequences.
- Broadcast: multiple listeners, events replayed only to active listeners. Use
.asBroadcastStream()orStreamController<T>.broadcast().
2. Always Cancel Subscriptions
Leaking subscriptions causes memory leaks and duplicate work.
class _MyScreenState extends State<MyScreen> {
StreamSubscription<Event>? _sub;
@override
void initState() {
super.initState();
_sub = bus.events.listen(_handle);
}
@override
void dispose() {
_sub?.cancel();
super.dispose();
}
}
In widgets, prefer StreamBuilder — it cancels automatically on dispose.
3. StreamController Patterns
class SearchController {
final _queries = StreamController<String>.broadcast();
Stream<String> get queries => _queries.stream;
void submit(String q) => _queries.add(q);
Future<void> dispose() => _queries.close();
}
- Always
close()the controller when done. - Expose
Stream<T>, notStreamController<T>, to consumers.
4. Transforming Streams
repo.watchArticles()
.where((list) => list.isNotEmpty)
.map((list) => list.first)
.distinct()
.listen(_handle);
For richer operators (debounce, throttle, combineLatest, switchMap), use rxdart:
queries
.debounceTime(const Duration(milliseconds: 300))
.distinct()
.switchMap((q) => repo.search(q).asStream())
.listen(_renderResults);
5. async*/yield
Use generator functions for custom streams:
Stream<int> countdown(int from) async* {
for (var i = from; i > 0; i--) {
yield i;
await Future<void>.delayed(const Duration(seconds: 1));
}
}
6. Error Handling
.listen(onData, onError: ..., cancelOnError: false)— decide whether an error should terminate the subscription.- In
async*generators, throw to propagate an error to the listener. - In
StreamBuilder, always handlesnapshot.hasError.
7. Back-Pressure
Dart streams have no built-in back-pressure for broadcast streams. If a producer is faster than the consumer:
- Debounce, throttle, or sample (
rxdart). - Buffer with a bounded queue and drop or merge.
8. Testing
Use the test package with expectLater(stream, emitsInOrder([...])) and StreamMatchers (emits, emitsDone, emitsError).
9. Checklist
- Every
listenhas a matchingcancel(or usesStreamBuilder). - Every
StreamControllerisclose()d. - Public API exposes
Stream<T>, not the controller. - Errors on the stream are handled, not ignored.
-
distinct()used where duplicate events cause unnecessary work.