我正在使用 BLoC 从 Firestore 加载预设对象。这是我的块模型:
class StatisticsBloc extends BlocBase {
List<Preset> _presets;
StreamController<List<Preset>> _presetsController = new StreamController();
Stream<List<Preset>> get getPresets => _presetsController.stream.asBroadcastStream();
StatisticsBloc() {
print('init Statistics Bloc');
_presets = [];
Firestore.instance.collection('Presets').snapshots().asBroadcastStream().listen(_onPresetsLoaded);
}
@override
void dispose() {
print('Disposed Statistics Bloc');
_presetsController.close();
}
void _onPresetsLoaded(QuerySnapshot data) {
_presets = [];
data.documents.forEach((DocumentSnapshot snap) {
Preset preset = Preset.fromDoc(snap);
_presets.add(preset);
});
_presetsController.sink.add(_presets);
}
}
然后我像这样显示列表:
class StatisticsPage extends StatelessWidget {
StatisticsPage() {
print('Created StatisticsPage');
}
@override
Widget build(BuildContext context) {
final StatisticsBloc statisticsBloc = BlocProvider.of<StatisticsBloc>(context);
final List<Preset> _ = [];
print(statisticsBloc.getPresets.isBroadcast);
return Scaffold(
appBar: AppBar(
title: Text('Statistics'),
),
body: StreamBuilder(
stream: statisticsBloc.getPresets,
initialData: _,
builder: (BuildContext context, AsyncSnapshot<List<Preset>> snapshot) {
if (snapshot.hasData) {
return ListView(
children: snapshot.data.map((Preset preset) {
print(preset.name);
return new ListTile(
title: new Text(preset.name),
subtitle: new Text(preset.id),
);
}).toList(),
);
} else {
Text('No Data');
print('No Data');
}
}
)
);
}
}
问题是,我展示了StatisticsPage
在选项卡栏中,因此当我切换选项卡并返回到它时,它将被多次构建。第一次访问时它可以工作,但是当我切换选项卡并返回到它时,小部件会重建并且出现错误:Bad state: Stream has already been listened to.
。我试图声明getPresets
作为 BroadcastStream 进行流式传输,如您所见StatisitcsBloc
但这行不通。
另外作为次要问题:是否有更好的方法来转型Stream<QuerySnapshot>
我从 Firestore 得到的Stream<List<Presets>>
?
很简单,看看行为主体类 from RxDart 库.
默认情况下,BehaviorSubject 是一个广播(又名热)控制器,以履行 Rx subject 契约。这意味着主题的流可以被多次收听。
所以,只需更改线路
StreamController<List<Preset>> _presetsController = new StreamController();
to
StreamController<List<Preset>> _presetsController = new BehaviorSubject();
并删除所有
.asBroadcastStream()
就是这样!
官方文档中是这样的不建议使用 asBroadcastStream()
创建流控制器的一种更危险的方法是通过 asBroadcastStream() 查看单订阅控制器。调用 asBroadcastStream 基本上告诉单订阅流用户想要接管流的生命周期管理。与 cancelOnError 订阅者结合使用,这很容易导致单流订阅永远不会关闭,从而泄漏内存或资源。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)