如何在同一个块中等待多个块事件

Posted

技术标签:

【中文标题】如何在同一个块中等待多个块事件【英文标题】:How to wait multiple bloc events in same bloc 【发布时间】:2021-04-28 08:09:54 【问题描述】:

我有一个包含多个事件的集团。在这里,我加载类别和位置并使用BlocListener 等待。但是我的显示循环进度指示器的条件不正确,并且在加载类别和位置之后也显示。在这种情况下如何正确使用 bloc?

代码

apiDataBloc.add(LoadCategoriesEvent());
apiDataBloc.add(LoadLocationsEvent());

------------------------

return BlocListener<ApiDataBloc, ApiDataState>(
  listener: (context, state) 
    if (state is CategoriesLoaded) 
      categories = state.categories;
      print("Categories loaded");
      print(categories.length);
    
  ,
  child: BlocListener<ApiDataBloc, ApiDataState>(
    listener: (context, s) 
      if (s is LocationsLoaded) 
        locations = s.locations;
        print("Locations loaded");
        print(locations.length);
      
    ,
    child: locations != null &&
            categories != null &&
            categories.length > 0 &&
            locations.length > 0
        ? Container(child: Center(child: Text('Categories and locations loaded!')))
        : Container(child: Center(child: CircularProgressIndicator())),
  ),
);

我也尝试过这样,但不起作用。

return BlocProvider<ApiDataBloc>(
      create: (context) => apiDataBloc,
      child: BlocBuilder<ApiDataBloc, ApiDataState>(
        builder: (context, state) 
          if (state is LocationsLoaded) 
            print("Locations loaded");
            locations = state.locations;
            print(locations.length);
            return BlocBuilder<ApiDataBloc, ApiDataState>(
              builder: (context, s) 
                if (s is CategoriesLoaded) 
                  print("Categories loaded");
                  categories = s.categories;
                  print(categories.length);
                  return Container(
                      child: Center(
                          child: Text('Categories and locations loaded!')));
                
                return Container(
                    child: Center(child: CircularProgressIndicator()));
              ,
            );
          
          return Container(child: Center(child: CircularProgressIndicator()));
        ,
      ),
    );

【问题讨论】:

为什么这两个不同的事件,你可以在你的应用程序中只加载一个事件吗?为什么不只制作一个名为“LoadingData”的事件和一个状态“DataSuccessfullyLoaded”或类似的东西? 我创建了 1 个包含多个事件的块来从 api 加载数据。每个事件从 api 加载不同的数据。不可能等待来自同一个集团类的多个事件完成?或者你推荐的没有将事件组合到一个集团? @nvoigt 【参考方案1】:

我会将逻辑放入集团中。如果我理解正确,您会在加载数据后立即触发一个事件。然后您可以在 bool categoriesLoaded, locationsLoaded 块中创建 2 个变量,您在事件中将其设置为 true。在 mapEventToState 中,您可以从这些事件映射器中的每一个转发到一个公共事件映射器,该事件映射器检查两个变量是否为真,然后发送正确的状态。 inProgress 状态可以显示哪些数据流已经被加载。

【讨论】:

【参考方案2】:

您应该创建一个状态 DataLoaded,其中包含 2 个字段 categorieslocations

类似的东西:

class DataLoaded extends ApiDataState 

  const DataLoaded(
    this.categories,
    this.locations,
  );

  final List<Type> categories;
  final List<Type> locations;

  @override
  String toString() => 'DataLoaded';

然后你需要从ApiDataBloc类中的API获取数据:

class ApiDataBloc extends Bloc<YourEventType, ApiDataState> 
  ApiDataBloc() : super(YourInitialState());

  @override
  Stream<ApiDataState> mapEventToState(YourEventType event) async* 
    if (event is YourFetchApiEvent) 
      yield YourLoadingState();

      final categories = await _fetchCategories();
      final locations = await _fetchLocations();

      yield DataLoaded(categories,locations);
    
   
 

最后一步是 BlocBuilder 在您的小部件中:

return BlocProvider<ApiDataBloc>(
      create: (context) => apiDataBloc,
      child: BlocBuilder<ApiDataBloc, ApiDataState>(
        builder: (context, state) 
          if (state is YouLoadingState) 
            return Center(child: CircularProgressIndicator());
          
          if (state is DataLoaded) 
            print(state.locations);
            print(state.categories);
            return Center(
             child: Text('Categories and locations loaded!'),
            );
          
        ,
      ),
    );

【讨论】:

【参考方案3】:

我知道你的意思。

Example Case:
#some_bloc.dart (not in event or state file)
on<someEventNo1>((......) =>
   emit(LoadingState());
   emit(EmitResultAPI());

on<someEventNo2>((......) =>
   emit(LoadingState());
   emit(someState());

#main.dart
someMethod() 
   BlocProvider.of<SomeBloc>(context).add(someEventNo1());
   BlocProvider.of<SomeBloc>(context).add(someEventNo2());

如果你这样做你的代码,当someEventNo1发出EmitResultAPI时,bloc builder不会捕捉到状态变化,因为你连续发送2个BlocProvider.of&lt;&gt;()

解决方案:

BlocProvider.of<SomeBloc>(context).add(someEventNo1());
Future.delayed(Duration(miliseconds: 100)).then((valueFuture) => BlocProvider.of<SomeBloc>(context).add(someEventNo2()));

【讨论】:

以上是关于如何在同一个块中等待多个块事件的主要内容,如果未能解决你的问题,请参考以下文章

如何将来自多个翻译单元的多个 const 对象放置在一个内存块中?

同一位置块中的多个 if 如何交互?

Terraform:如何在单个资源块中提供多个 lambda 函数 zip 文件

如何取消颤振/飞镖集团中的“等待”

如何使用多个catch块处理异常

在synchronize代码块中调用wait后还会继续执行后续的代码吗