如何在同一个块中等待多个块事件
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 个字段 categories 和 locations
类似的东西:
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<>()
。
解决方案:
BlocProvider.of<SomeBloc>(context).add(someEventNo1());
Future.delayed(Duration(miliseconds: 100)).then((valueFuture) => BlocProvider.of<SomeBloc>(context).add(someEventNo2()));
【讨论】:
以上是关于如何在同一个块中等待多个块事件的主要内容,如果未能解决你的问题,请参考以下文章
如何将来自多个翻译单元的多个 const 对象放置在一个内存块中?