[英]Flutter: How to Use StreamBuilder With BlocBuilder in Case the Stream Is a Part of The Bloc's State?
I will use simplified version than that of my project but feel free to ask for more code if necessary.我将使用比我的项目更简单的版本,但如有必要,请随时要求提供更多代码。 This may be more of an architectural question.这可能更像是一个架构问题。
I have a service (interface) FooService
in my app which exposes a stream fooStream
.我的应用程序中有一个服务(接口) FooService
,它公开了一个流fooStream
。 I have this service as a member of the bloc class MyBloc
.我作为集团类MyBloc
的成员拥有这项服务。
Now the state of the bloc MyBlocState
contains isProcessing
to indicate if the bloc is processing and also it contains fooStream
field which expose the service's version of fooStream
to the UI layer (so there are 3 layers: service => bloc => UI).现在,块MyBlocState
的状态包含isProcessing
以指示块是否正在处理,它还包含fooStream
字段,该字段将服务的fooStream
版本fooStream
给 UI 层(因此有 3 个层:服务 => 块 => UI)。
The problem now is that when I want to listen to this service stream in my UI, I am forced to use a StreamBuilder
which itself will be wrapped inside a BlocBuilder
.现在的问题是,当我想在我的 UI 中收听此服务流时,我不得不使用StreamBuilder
,它本身将被包装在BlocBuilder
。 And this will become very messy in a large app.这在大型应用程序中会变得非常混乱。 So whats the best way to represent the fooStream
inside the bloc's state?那么在 bloc 的状态中表示fooStream
的最佳方式是什么? Can I just listen to the stream inside the bloc and add an event to the bloc whenever a fooStream
event arrives?我可以只收听 bloc 内部的流并在fooStream
事件到达时向 bloc 添加一个事件吗? Wouldn't this be a bad side effect where state will be updated in a messy way and changes in state can't be tracked anymore?在状态将以混乱的方式更新并且无法再跟踪状态变化的情况下,这不是一个糟糕的副作用吗?
Sample code:示例代码:
class FooService{
Stream fooStream;// the stream is exposed here
...
}
class MyBloc extends ... {
FooService myService = ...;//the service is used here as a member
...
}
class MyBlocState extends ... {
Stream? fooStream;//this value will hold the stream exposed from the service and it may be initialized in an init event in the bloc for example
...
}
and now in the UI I have to do this ugly thing (ugly because now I am listening to the state from 2 places, from the bloc and from the stream, which in my opinion defeats the purpose of the bloc as the sole entry point to change the state and maintain it in the UI/app):现在在 UI 中,我必须做这件难看的事情(丑陋,因为现在我正在从 2 个地方监听状态,从集团和来自流,在我看来,这违背了集团作为唯一入口点的目的更改状态并在 UI/应用程序中维护它):
Widget build(BuildContext context){
return BlocBuilder<MyBloc,MyBlocState>(
builder: (context, myBlocState) {
if(myBlocState is Loading){
return CircularProgressIndicator();
}
if(myBlocState is Error){
return ErrorWidget();
}
if(myBlocState is SomeState){
return StreamBuilder(//I need to wrap the StreamBuilder inside the BlocBuilder because the stream will be null when the app launches but then it will have a value which is fooStream when I call init in the bloc
stream: myBlocState.fooStream,
builder: (context, snapshot) {
if(snapshot.hasData){
return SomeWidget();
}
else{
return SomeOtherWidget();
}
},
);
}
},
)
}
The UI should ideally just be responding to state changes in your bloc so I highly recommend subscribing to the stream within the bloc and emitting states in response to data from the stream.理想情况下,UI 应该只响应您的 bloc 中的状态更改,因此我强烈建议订阅 bloc 中的流并发出状态以响应来自流的数据。 You can check out the timer example for a reference which manages the subscription in order to pause/resume.您可以查看计时器示例以获取管理订阅以暂停/恢复的参考。 In simple cases, you can use emit.forEach
or emit.onEach
in bloc >=7.2.0 which means you don't need to manually maintain a StreamSubscription
.在简单的情况下,您可以在 bloc >=7.2.0 中使用emit.forEach
或emit.onEach
,这意味着您不需要手动维护StreamSubscription
。
You can see an example of emit.onEach
in the flutter bloc with stream example and emit.forEach
would look very similar:你可以在flutter bloc中看到一个emit.onEach
的例子和stream example , emit.forEach
看起来非常相似:
class TickerBloc extends Bloc<TickerEvent, TickerState> {
TickerBloc(Ticker ticker) : super(TickerInitial()) {
on<TickerStarted>(
(event, emit) async {
await emit.forEach<int>(
ticker.tick(),
onData: (tick) => TickerTick(tick),
);
},
transformer: restartable(),
);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.