【问题标题】:Flutter: How to Use StreamBuilder With BlocBuilder in Case the Stream Is a Part of The Bloc's State?Flutter:如果 Stream 是 Bloc 状态的一部分,如何将 StreamBuilder 与 BlocBuilder 一起使用?
【发布时间】:2021-12-05 22:44:38
【问题描述】:

我将使用比我的项目更简化的版本,但如有必要,请随时询问更多代码。这可能更像是一个架构问题。

我的应用程序中有一个服务(接口)FooService,它公开了一个流 fooStream。我作为集团类MyBloc 的成员拥有这项服务。

现在 MyBlocState 块的状态包含 isProcessing 以指示块是否正在处理,并且它还包含 fooStream 字段,它将服务的 fooStream 版本暴露给 UI 层(所以有 3 层: service => bloc => UI)。

现在的问题是,当我想在我的 UI 中收听此服务流时,我不得不使用 StreamBuilder,它本身将被包裹在 BlocBuilder 中。这在大型应用程序中会变得非常混乱。那么在欧盟国家内部代表fooStream 的最佳方式是什么?每当fooStream 事件到达时,我可以只收听集团内的流并向集团添加一个事件吗?如果状态将以混乱的方式更新并且无法再跟踪状态的变化,这不是一个不好的副作用吗?

示例代码:

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

  ...

}

现在在 UI 中我必须做这个丑陋的事情(丑陋,因为现在我正在从两个地方听状态,从集团和流,在我看来,这违背了集团作为唯一的目的在 UI/app 中更改状态和维护状态的入口点):

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();
            }
          },
        );
      }
    },
  )
}

【问题讨论】:

    标签: java ios flutter dart architecture


    【解决方案1】:

    理想情况下,UI 应该只响应您的 bloc 中的状态更改,因此我强烈建议订阅 bloc 中的流并发出状态以响应来自流的数据。您可以查看timer example 以获取管理订阅以暂停/恢复的参考。在简单的情况下,您可以在 bloc >=7.2.0 中使用emit.forEachemit.onEach,这意味着您无需手动维护StreamSubscription

    您可以在flutter bloc with stream example 中看到emit.onEach 的示例,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(),
        );
      }
    }
    

    【讨论】:

    • 啊,所以诀窍是定义一个对 bloc 类私有的事件并使用emit.forEach 监听流,然后我从那里add 这个私有事件反过来将导致发射状态代表流中的新值。我不知道这种方法存在,非常感谢:)
    猜你喜欢
    • 2020-03-09
    • 2021-03-19
    • 2019-12-28
    • 2021-03-15
    • 1970-01-01
    • 2019-05-24
    • 2020-07-21
    • 2020-04-26
    • 2020-03-10
    相关资源
    最近更新 更多