Flutter报错:无法找到正确的Provider<ManageBloc>求助
问题描述
使用Bloc开发Flutter应用时,点击浮动按钮打开NewOperation组件,出现错误提示:Could not find the correct Provider<ManageBloc>。已尝试将浮动按钮放入MultiBlocProvider中,但问题仍未解决。
main.dart 代码
class _MyHomePageState extends State<MyHomePage> { final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); @override Widget build(BuildContext context) { return MultiBlocProvider( providers: [ BlocProvider(create: (_) => ManageBloc()), BlocProvider(create: (_) => MonitorBloc()), ], child: Builder( builder: (context) => Scaffold( appBar: AppBar( title: Row(children: [ const Icon(Icons.wallet), Text(widget.title), ]), bottom: const TabBar(tabs: [ Tab(icon: Icon(Icons.home)), Tab(icon: Icon(Icons.compare_arrows)), Tab(icon: Icon(Icons.monetization_on)) ]), ), body: const TabBarView( children: [ HomeScreen(), OperationsView(), PricesScreen(), ]), floatingActionButton: FloatingActionButton( onPressed: () { showModalBottomSheet(context: context, builder: (BuildContext context) { return NewOperation(); }); }, hoverColor: Colors.white, backgroundColor: Colors.white10, child: const Icon(Icons.add, color: Colors.lightBlue), ), ), )); } }
NewOperation 代码
class NewOperation extends StatelessWidget { final GlobalKey<FormState> _formKey = GlobalKey(); final Operation operation = Operation(); bool _isEntry = false; @override Widget build(BuildContext context) { return BlocBuilder<ManageBloc, ManageState>(builder: (context, state) { Operation operation; if (state is UpdateState) { operation = state.previousOperation; } else { operation = Operation(); } return Form( key: _formKey, child: Column( children: [ TextFormField( keyboardType: const TextInputType.numberWithOptions( decimal: true), validator: (String? inValue) { if (inValue != null) { if (double.parse(inValue) <= 0.0) { return "Valor inválido!"; } } return null; }, decoration: const InputDecoration( hintText: "00.0", labelText: "Valor da Operação", ), ), TextFormField( keyboardType: TextInputType.multiline, validator: (String? inValue) { if (inValue != null) { if (inValue.length < 3) { return "Addiction uma descrição mais detalhada!"; } } return null; }, decoration: const InputDecoration( hintText: "Conta de luz", labelText: "Descrição", ), ), Row(children: [ const Text("Entrada"), Switch(value: _isEntry, onChanged: (bool inValue) { // handleIsEntry(inValue); }), const Text("Saída"), ]), ElevatedButton(onPressed: () { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); BlocProvider.of<ManageBloc>(context).add(SubmitEvent(operation: operation)); _formKey.currentState!.reset(); } }, child: const Text("Salvar")) ], )); }); } }
问题原因与解决方案
核心原因
showModalBottomSheet使用的context是_MyHomePageState的上下文,这个上下文位于MultiBlocProvider的父级范围,无法访问到MultiBlocProvider内部提供的ManageBloc实例。即使浮动按钮在MultiBlocProvider子树里,传递给弹窗的上下文依然是外层的,导致NewOperation中的BlocBuilder找不到Provider。
两种解决方法
方法一:获取MultiBlocProvider内部的上下文
用Builder包裹浮动按钮,确保传递给showModalBottomSheet的是MultiBlocProvider子树内的上下文:
floatingActionButton: Builder( builder: (innerContext) => FloatingActionButton( onPressed: () { showModalBottomSheet( context: innerContext, builder: (_) => NewOperation(), ); }, hoverColor: Colors.white, backgroundColor: Colors.white10, child: const Icon(Icons.add, color: Colors.lightBlue), ), ),
方法二:在弹窗内复用已有的Bloc实例
直接在弹窗的builder中使用BlocProvider.value传递已有的ManageBloc:
floatingActionButton: FloatingActionButton( onPressed: () { showModalBottomSheet( context: context, builder: (_) => BlocProvider.value( value: BlocProvider.of<ManageBloc>(context), child: NewOperation(), ), ); }, // 其余属性不变 ),
额外优化建议
- 简化Bloc调用:
NewOperation中可以用context.read<ManageBloc>()替代BlocProvider.of<ManageBloc>(context),代码更简洁:ElevatedButton( onPressed: () { if (_formKey.currentState!.validate()) { _formKey.currentState!.save(); context.read<ManageBloc>().add(SubmitEvent(operation: operation)); _formKey.currentState!.reset(); } }, child: const Text("Salvar"), ) - 避免变量重名:
NewOperation中类级别的operation和BlocBuilder内部的operation重名,建议修改内部变量名(比如改为currentOperation),避免逻辑混淆。
内容的提问来源于stack exchange,提问作者Robson Fischer
相关产品推荐
相关产品推荐

