Flutter : stream two Streams into a single screen? Flutter : stream two Streams into a single screen? dart dart

Flutter : stream two Streams into a single screen?


You can nest StreamBuilder if needed. Nothing prevents you from doing the following:

StreamBuilder(  stream: stream1,  builder: (context, snapshot1) {    return StreamBuilder(      stream: stream2,      builder: (context, snapshot2) {        // do some stuff with both streams here      },    );  },)

Another solution if this makes sense for you is: Streams are designed to be mergeable/transformed. You could make a third stream that is a merge of the two later streams.

Ideally for complex stream operations you'll want to use rxdart as it provides a few useful transformer.

Using rxdart, the fusion of two Observable (which are subclass of Stream) would be the following:

Observable<bool> stream1;Observable<String> stream2;final fusion = stream1.withLatestFrom(stream2, (foo, bar) {  return MyClass(foo: foo, bar: bar);});


Observable.combineLatest2(        aStream,        bStream,        (a, b, c) =>        a != '' && b != '');

combineLatestN returns a combined stream


I'm using a sort of BLoC where I have broadcast Stream<Null>s that just notify listeners when certain things change. Kind of like Qt's signals & slots. Anyway for the case where I want to listen to more than one stream I made this class. It's basically StreamBuilder but you can listen to more than one stream, and it discards any data from the streams.

import 'dart:async';import 'package:flutter/widgets.dart';typedef MultiStreamWidgetBuilder<T> = Widget Function(BuildContext context);// A widget that basically re-calls its builder whenever any of the streams// has an event.class MultiStreamBuilder extends StatefulWidget {  const MultiStreamBuilder({    required this.streams,    required this.builder,    Key? key,  }) : super(key: key);  final List<Stream<dynamic>> streams;  final MultiStreamWidgetBuilder builder;  Widget build(BuildContext context) => builder(context);  @override  State<MultiStreamBuilder> createState() => _MultiStreamBuilderState();}class _MultiStreamBuilderState extends State<MultiStreamBuilder> {  final List<StreamSubscription<dynamic>> _subscriptions = [];  @override  void initState() {    super.initState();    _subscribe();  }  @override  void didUpdateWidget(MultiStreamBuilder oldWidget) {    super.didUpdateWidget(oldWidget);    if (oldWidget.streams != widget.streams) {      // Unsubscribe from all the removed streams and subscribe to all the added ones.      // Just unsubscribe all and then resubscribe. In theory we could only      // unsubscribe from the removed streams and subscribe from the added streams      // but then we'd have to keep the set of streams we're subscribed to too.      // This should happen infrequently enough that I don't think it matters.      _unsubscribe();      _subscribe();    }  }  @override  Widget build(BuildContext context) => widget.build(context);  @override  void dispose() {    _unsubscribe();    super.dispose();  }  void _subscribe() {    for (final s in widget.streams) {      final subscription = s.listen(        (dynamic data) {          setState(() {});        },        onError: (Object error, StackTrace stackTrace) {          setState(() {});        },        onDone: () {          setState(() {});        },      );      _subscriptions.add(subscription);    }  }  void _unsubscribe() {    for (final s in _subscriptions) {      s.cancel();    }    _subscriptions.clear();  }}

Example use:

class AppWidget extends StatelessWidget {  @override  Widget build(BuildContext context) {    return MultiStreamBuilder(      streams: [appState.repoListChanged, appState.selectedRepoChanged],      builder: _buildMain,    );  }  Widget _buildMain(BuildContext context) {    return Scaffold(      body: Row(...

I only just wrote it, so I haven't tested it much. I think in theory you could make one that gives you the states, though I'm not sure Dart's type system is advanced enough to let you do it without resorting to dynamic all over the place.