我有两个流从两个不同的api获取。
Stream<Month> get monthOutStream => monthOutController.stream;
Stream<MySchedule> get resultOutStream => resultController.stream;
我正在应用程序的两种不同状态下获取这些数据,这是在用户发生一些事件后的开始和几个月后得出的结果。
MyScheduleBloc(){
initialData();
}
Future initialData() async {
MySchedule mySchedule = await myScheduleViewModel.importMySchedule(now.id);
resultController.add(mySchedule);
}
我的屏幕上的流生成器为
Widget build(BuildContext context) {
final webCalenderBloc = WebCalenderBloc();
return StreamBuilder(
stream: webCalenderBloc.resultOutStream,
builder: (BuildContext context , snapdata){
if(!snapdata.hasData){
return Center(
child: CircularProgressIndicator(),
);
}
return body(snapdata.data);
},
);
}
因为主要的窗口小部件构建方法将带有resultoutstream的StreamBuilder窗口小部件作为流。我在哪里获取另一个流monthoutStream。 我可以在流中获取流吗?我在处理两个流时会丢失任何东西吗?我不想从monthoutstream构建任何小部件,但想检查其中的数据。
答案 0 :(得分:13)
如果需要,您可以嵌套StreamBuilder
。没有什么可以阻止您执行以下操作:
StreamBuilder(
stream: stream1,
builder: (context, snapshot1) {
return StreamBuilder(
stream: stream2,
builder: (context, snapshot2) {
// do some stuff with both streams here
},
);
},
)
这对您有意义的另一种解决方案是:流被设计为可合并/转换的。您可以制作第三个流,该流是后面两个流的合并。
理想地,对于复杂的流操作,您将希望使用rxdart,因为它提供了一些有用的转换器。
使用rxdart,将两个Observable
(它们是Stream
的子类)的融合如下:
Observable<bool> stream1;
Observable<String> stream2;
final fusion = stream1.withLatestFrom(stream2, (foo, bar) {
return MyClass(foo: foo, bar: bar);
});
答案 1 :(得分:1)
Observable.combineLatest2(
aStream,
bStream,
(a, b, c) =>
a != '' && b != '');
combineLatestN返回组合流
答案 2 :(得分:1)
我正在使用一种 BLoC,其中我广播了 Stream<Null>
,它只是在某些事情发生变化时通知听众。有点像 Qt 的信号和插槽。无论如何,对于我想听不止一个流的情况,我做了这门课。它基本上是 StreamBuilder
,但您可以收听多个流,它会丢弃流中的任何数据。
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();
}
}
示例使用:
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(
...
我只是写了它,所以我没有太多测试。我认为从理论上讲,您可以制作一个为您提供状态的系统,尽管我不确定 Dart 的类型系统是否先进到足以让您无需到处求助于 dynamic
就可以做到这一点。
答案 3 :(得分:0)
在我的情况下,我更喜欢将多个流合并到一个流中,如果它们来自同一类型,那么您可以使用:
import 'package:async/async.dart' show StreamGroup;
...
StreamGroup.merge([stream1,stream2]);