在对话框中使用 BLoC:找不到正确的提供程序

Posted

技术标签:

【中文标题】在对话框中使用 BLoC:找不到正确的提供程序【英文标题】:Using BLoC in a dialog: Could not find the correct Provider 【发布时间】:2021-02-24 18:56:05 【问题描述】:

我正在尝试使用块来管理对话框的内容。我对 Flutter 还很陌生。

页面定义为:

@override
Widget build(BuildContext context) 
  return Scaffold(
    appBar: AppBar(
      title: Text("Business Region Manager"),
    ),
    body: MultiBlocProvider(
      providers: [
        BlocProvider(
          create: (context) =>
              EntityModifyBloc(repository: widget.repository),
        ),
        BlocProvider(
          create: (context) => EntityBloc(
              repository: widget.repository,
              modifyBloc: BlocProvider.of<EntityModifyBloc>(context)),
        ),
        BlocProvider(
          create: (context) => BusinessRegionBloc(repository: widget.repository),
        ),
      ],
      child: Center(
        child: BusinessRegionPage(widget.business),
      ),
    ));

在 BusinessRegionPage 内部,我使用了 EntityBloc 和 EntityModifyBloc,并且至少我认为我是正确的。 该页面有一个回调,在触发时会调用一个方法:

void onAddBusinessRegion()
  showDialog(context: context,
    barrierDismissible: false,
    builder: (BuildContext context)
      return BusinessRegionDialog(
        positiveText: "Ok",
        onPositive: onPositive,
        negativeText: 'Cancel',
        onNegative: onNegative,
        businessId: widget.business.id,
      );
    );

BusinessRegionDialog 是一个有状态的小部件,状态实现构建是:

@override
Widget build(BuildContext context) 
  return BlocBuilder<BusinessRegionBloc, BusinessRegionState>(builder: (context, state) 
    if (state is BusinessRegionEmpty) 
      BlocProvider.of<BusinessRegionBloc>(context).add(GetBusinessRegions(widget.businessId));
    
    if (state is BusinessRegionError) 
      return Center(
        child: Text('Busines Region Error'),
      );
    
    if (state is BusinessRegionLoaded) 
      return Center(
        child: Text('BusinessRegionLoaded'),
      );
    
    return Center(
      child: CircularProgressIndicator(),
    );
  );

当回调被触发时,我收到消息:

错误:在此 BlocBuilder 小部件上方找不到正确的提供程序

这可能是因为您使用了不包含提供程序的BuildContext 您的选择。

我假设在调用 ShowDialog(context) 时,上下文与传递给 build 的上下文相同?我通过在 showDialog 调用之前和 BusinessRegionPage 上的构建实现之后打印上下文的 hashCode 来检查这个假设,

错误消息中的一个建议是:

Widget build(BuildContext context) 
  return Provider<Example>(
    create: (_) => Example(),
    builder: (context) 
      return Text(context.watch<Example>()),
    
  ),

所以我尝试了:

void onAddBusinessRegion() 
  print("OnAddCallback: " + context.hashCode.toString());
  BusinessRegionClient brClient = BusinessRegionClient(client: http.Client());
  BusinessRegionRepository brRepository =
      BusinessRegionRepository(client: brClient);

  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (BuildContext context) 
      return Provider<BusinessRegionBloc>(
          create: (_) => BusinessRegionBloc(repository: brRepository),
          builder: (context) 
            return BusinessRegionDialog(
              positiveText: "Ok",
              onPositive: onPositive,
              negativeText: 'Cancel',
              onNegative: onNegative,
              businessId: widget.business.id,
            );
          );
    );

IDE 告诉我: 参数类型“BusinessRegionDialog Function(BuildContext)”不能分配给参数类型“Widget Function(BuildContext, Widget)”。

我显然不明白一些事情。我要做的就是用我的存储库中的 Future 信息填充一个对话框。任何指导将不胜感激。

【问题讨论】:

【参考方案1】:

多亏了so条目,我终于弄明白了:

Flutter: bloc, how to show an alert dialog

这里的答案是使用堆栈让对话框和页面共存,并在侦听器具有正确状态时显示对话框。答案使用 StatelessWidget 来管理,就答案而言,是 SnackBar。为了能够向 bloc 添加事件,我使用了 StatefulWidget。

@override
Widget build(BuildContext context) 
  return Scaffold(
    appBar: AppBar(
    title: Text("Business Region Manager"),
    ),
    body: MultiBlocProvider(
      providers: [
        BlocProvider(
          create: (context) => EntityModifyBloc(
              repository: xbrRepository), //widget.repository),
        ),
        BlocProvider(
          create: (context) => EntityBloc(
              repository: xbrRepository, //widget.repository,
              modifyBloc: BlocProvider.of<EntityModifyBloc>(context)),
        ),
        BlocProvider(
          create: (context) => BusinessRegionDialogBloc(
              repository: xbrRepository),
        ),
      ],
      child: Stack(children: [
        BusinessRegionDialogManager(widget.business.id),
        Center(child: BusinessRegionPage(widget.business)),
      ]),
    ));


class BusinessRegionDialogManager extends StatefulWidget 
  final int businessId;

  BusinessRegionDialogManager(this.businessId);

  State<BusinessRegionDialogManager> createState() =>
    _BusinessRegionDialogManagerState();

类 _BusinessRegionDialogManagerState 扩展状态

// Callback functions from the dialog so can have access to
// BusinessRegionDialogBloc
void xnPositive(List<Region> addedRegions) 
    BlocProvider.of<BusinessRegionDialogBloc>(context)
      .add(AddBusinessRegions(addedRegions, widget.businessId));


void xnNegative()



@override
Widget build(BuildContext context) 
  return BlocListener<BusinessRegionDialogBloc, BusinessRegionDialogState>(
    listener: (context, state) 
      if (state is RegionDialogLoaded) 
        showDialog(
          context: context,
          barrierDismissible: false,
          builder: (BuildContext context) 
            return BusinessRegionDialog(
              onPositive: xnPositive,
              onNegative: xnNegative,
              regions: state.regions,
            );
          )
      
    ,
    child: Container(),
  );

【讨论】:

【参考方案2】:

i solved it as like this

你要做的是创建一个 BlocTypeA 的提供者将它传递给孩子。创建一个 带有另一个上下文的对话框2 使用 provider.value 然后传递 bloc 使用 context2 构建它的子组件并在子小部件内部使用先前的上下文访问 bloc .read with BlocTypeA... 因此它解决了

【讨论】:

以上是关于在对话框中使用 BLoC:找不到正确的提供程序的主要内容,如果未能解决你的问题,请参考以下文章

MultiBlocProvider 未实例化所有 bloc 提供程序 - 如何正确使用 MultiBlocProvider?

Flutter:bloc,如何显示警报对话框

使用 Provider 向整个 Flutter 模块全局提供 BLoC

依赖项目中引入aar包,编译时提示找不到引入的aar包

在此小部件上方找不到正确的提供程序

Flutter cubit blocprovider 找不到正确的提供者