StreamBuilder仅接收流中的最后一项 [英] StreamBuilder receives only last item from stream
问题描述
我的ApplicationBloc是小部件树的根.在Bloc的构造函数中,我正在侦听来自存储库的流,该存储库包含从JSON解码的模型,并将其转发到StreamBuilder侦听的另一个流.
My ApplicationBloc is the root of the widget tree. In the bloc's constructor I'm listening to a stream from a repository that contains models decoded from JSON and forwarding them to another stream which is listened to by StreamBuilder.
我希望StreamBuilder会一一接收模型并将其添加到AnimatedList中.但这是一个问题:StreamBuilder的生成器仅对流中的最后一项触发一次.
I expected that StreamBuilder would receive models one by one and add them to AnimatedList. But there's the problem: StreamBuilder's builder fires only once with the last item in the stream.
例如,多个模型位于id为0、1、2和3的本地存储中.所有这些都是从存储库发出的,所有这些都已成功放入流控制器中,但只有最后一个模型(id为== 3)出现在AnimatedList中.
For example, several models lay in the local storage with ids 0, 1, 2 and 3. All of these are emitted from repository, all of these are successfully put in the stream controller, but only the last model (with id == 3) appears in the AnimatedList.
存储库:
class Repository {
static Stream<Model> load() async* {
//...
for (var model in models) {
yield Model.fromJson(model);
}
}
}
集团:
class ApplicationBloc {
ReplaySubject<Model> _outModelsController = ReplaySubject<Model>();
Stream<Model> get outModels => _outModelsController.stream;
ApplicationBloc() {
TimersRepository.load().listen((model) => _outModelsController.add(model));
}
}
main.dart:
main.dart:
void main() {
runApp(
BlocProvider<ApplicationBloc>(
bloc: ApplicationBloc(),
child: MyApp(),
),
);
}
//...
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
final ApplicationBloc appBloc = //...
return MaterialApp(
//...
body: StreamBuilder(
stream: appBloc.outModels,
builder: (context, snapshot) {
if (snapshot.hasData) {
var model = snapshot.data;
/* inserting model to the AnimatedList */
}
return AnimatedList(/* ... */);
},
),
);
}
}
有趣的通知:在StreamBuilder的_subscribe()方法中,onData()回调触发所需的次数,但build()方法仅触发一次.
Interesting notice: in the StreamBuilder's _subscribe() method onData() callback triggers required number of times but build() method fires only once.
推荐答案
您需要一个输出List<Model
而不是单个元素的Stream
.另外,侦听流以将其添加到另一个ReplaySubject
会将输出流延迟2(!!!)帧,因此最好使用单个链.
You need a Stream
that outputs a List<Model
instead of a single element. Also, listening to a stream to add it to another ReplaySubject
will delay the output stream by 2 (!!!) frames, so it would be better to have a single chain.
class TimersRepository {
// maybe use a Future if you only perform a single http request!
static Stream<List<Model>> load() async* {
//...
yield models.map((json) => Model.fromJson(json)).toList();
}
}
class ApplicationBloc {
Stream<List<Model>> get outModels => _outModels;
ValueConnectableObservable<List<Model>> _outModels;
StreamSubscription _outModelsSubscription;
ApplicationBloc() {
// publishValue is similar to a BehaviorSubject, it always provides the latest value,
// but without the extra delay of listening and adding to another subject
_outModels = Observable(TimersRepository.load()).publishValue();
// do no reload until the BLoC is disposed
_outModelsSubscription = _outModels.connect();
}
void dispose() {
// unsubcribe repo stream on dispose
_outModelsSubscription.cancel();
}
}
class _MyAppState extends State<MyApp> {
ApplicationBloc _bloc;
@override
Widget build(BuildContext context) {
return StreamBuilder<List<Model>>(
stream: _bloc.outModels,
builder: (context, snapshot) {
final models = snapshot.data ?? <Model>[];
return ListView.builder(
itemCount: models.length,
itemBuilder: (context, index) => Item(model: models[index]),
);
},
);
}
}
这篇关于StreamBuilder仅接收流中的最后一项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!