简体   繁体   English

Flutter:如果流是 Bloc 状态的一部分,如何将 StreamBuilder 与 BlocBuilder 一起使用?

[英]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.forEachemit.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 exampleemit.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.

相关问题 将文件的一部分用于File [Input / Output] Stream - Use part of a file for File[Input/Output]Stream 在这个涉及将实体 class 实例转换为 DTO 实例的用例中,如何正确使用 stream map()? - How can I correctly use the stream map() in this use case involving the conversion of an entity class instance into a DTO instance? 我有2个POJO的大学和学院。 学院有一套流。 在这种情况下,如何制作对应于Pojo的正确json? - I have 2 POJO's college and stream. College has a Set of stream. How to make correct json corresponding to Pojo in this case? 收集流时如何使用 Guava 的 Multisets.toMultiSet()? - How to use Guava's Multisets.toMultiSet() when collecting a stream? 有限状态机是此用例的正确选择吗? - Is Finite State Machine the correct choice for this use case? 如何使用find()而不更改Matcher的状态? - How to use find() without changing​ the Matcher's state? 在这种情况下,中间流和终端流方法如何工作 - How intermediate and terminal stream methods works in this case 如何在流中使用If语句? - How to use If statements in a stream? 在这种情况下如何使用迭代器? - How to use an iterator in this case? 在这种情况下如何使用“endText”? - How to use "endText" in this case?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM