我正在使用BLoC模式开发一个新的Flutter Mobile应用程序。但是我有一个问题,我还没有找到解决方案。
第一个是我的主页(使用MultiBlocProvider) 当我按下FloatingActionButton时。 它推送一个新屏幕以添加新的“ FicheMvt” 当我点击添加按钮。 它使用onSave回调函数来通知其父项新创建的“ FicheMvt” 它给了我一个错误。
在不包含Bloc的上下文中调用BlocProvider.of() 类型为FicheMvtBloc。
从所传递的上下文开始找不到祖先 到BlocProvider.of()。
如果您使用的上下文来自上方的小部件,则可能会发生这种情况 BlocProvider。
这是主页(呈现5个标签页)
class EtatCollecteScreen extends StatelessWidget {
final FicheMvtDAO ficheMvtDAO = FicheMvtDAO();
final FicheMvtReferenceDAO ficheMvtReferenceDAO = FicheMvtReferenceDAO();
@override
Widget build(BuildContext context) {
final FicheModel fiche = ModalRoute.of(context).settings.arguments;
return MultiBlocProvider(
providers: [
BlocProvider<TabEtatCollecteBloc>(
create: (context) => TabEtatCollecteBloc(),
),
BlocProvider<FicheMvtBloc>(
create: (context) => FicheMvtBloc(
ficheMvtDAO: ficheMvtDAO,
)..add(FicheMvtRequested(idFiche: fiche.id)),
),
BlocProvider<FicheMvtReferenceBloc>(
create: (context) => FicheMvtReferenceBloc(
ficheMvtReferenceDAO: ficheMvtReferenceDAO,
)..add(FicheMvtReferenceRequested(idFiche: fiche.id)),
),
],
child: EtatCollecteContent(
ficheModel: fiche,
),
);
}
}
class EtatCollecteContent extends StatelessWidget {
final FicheModel ficheModel;
const EtatCollecteContent({Key key, @required this.ficheModel});
@override
Widget build(BuildContext context) {
return BlocBuilder<TabEtatCollecteBloc, EtatCollecteTab>(
builder: (context, activeTab) {
return Scaffold(
appBar: AppBar(
title: Text("${ficheModel.id} - ${ficheModel.description}"),
actions: <Widget>[
RefreshMvtButton(
visible: activeTab == EtatCollecteTab.completed,
ficheModel: ficheModel,
),
SendMvtButton(
visible: activeTab == EtatCollecteTab.uncommitted,
ficheModel: ficheModel,
),
],
),
body: EtatCollecteBody(
activeTab: activeTab,
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return FicheMvtAddScreen(onSaveCallback: (idFiche, indicateurModel, codeSite) {
BlocProvider.of<FicheMvtBloc>(context).add(
FicheMvtAdded(
idFiche: idFiche,
indicateurModel: indicateurModel,
codeSite: codeSite,
),
);
});
},
settings: RouteSettings(
arguments: ficheModel,
),
),
);
},
child: Icon(Icons.add),
tooltip: "Add",
),
bottomNavigationBar: TabEtatCollecteSelector(
activeTab: activeTab,
onTabSelected: (tab) => BlocProvider.of<TabEtatCollecteBloc>(context).add(TabEtatCollecteUpdated(tab)),
),
);
},
);
}
}
这是表单的代码,用于添加新的“ FicheMvt”,其中包含另一个管理动态表单的块(FicheMvtAddBloc)。
typedef OnSaveCallback = Function(
int idFiche,
IndicateurModel indicateurModel,
String codeSite,
);
class FicheMvtAddScreen extends StatelessWidget {
final OnSaveCallback onSaveCallback;
const FicheMvtAddScreen({Key key, @required this.onSaveCallback}) : super(key: key);
@override
Widget build(BuildContext context) {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final FicheModel fiche = ModalRoute.of(context).settings.arguments;
final FicheMvtRepository ficheMvtRepository = FicheMvtRepository();
return Scaffold(
key: _scaffoldKey,
appBar: new AppBar(
title: new Text("${fiche.id} - ${fiche.description}"),
),
backgroundColor: Colors.white,
body: BlocProvider<FicheMvtAddBloc>(
create: (context) => FicheMvtAddBloc(
ficheMvtRepository: ficheMvtRepository,
idFiche: fiche.id,
)..add(NewFicheMvtFormLoaded(idFiche: fiche.id)),
child: FicheMvtAddBody(
ficheModel: fiche,
onSave: onSaveCallback,
),
),
);
}
}
这是表格的内容
class FicheMvtAddBody extends StatefulWidget {
final FicheModel ficheModel;
final OnSaveCallback onSave;
@override
_FicheMvtAddBodyState createState() => _FicheMvtAddBodyState();
FicheMvtAddBody({Key key, @required this.ficheModel, @required this.onSave});
}
class _FicheMvtAddBodyState extends State<FicheMvtAddBody> {
static final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
void _onIndicateurChanged(String indicateur) =>
BlocProvider.of<FicheMvtAddBloc>(context).add(NewFicheMvtIndicateurChanged(indicateur: indicateur));
void _onSiteChanged(String site) => BlocProvider.of<FicheMvtAddBloc>(context).add(NewFicheMvtSiteChanged(site: site));
final FicheModel fiche = ModalRoute.of(context).settings.arguments;
final txtIndicateur = Text("Indicateur");
final txtSite = Text("Site");
return BlocBuilder<FicheMvtAddBloc, FicheMvtAddState>(
builder: (context, state) {
return Form(
key: _formKey,
child: Center(
child: ListView(
shrinkWrap: true,
padding: EdgeInsets.only(left: 24.0, right: 24.0),
children: <Widget>[
SizedBox(height: 24.0),
txtIndicateur,
DropdownButtonFormField<String>(
isExpanded: true,
hint: Text("Choisissez l'indicateur"),
value: state.indicateur?.code ?? null,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
onChanged: (String newValue) {
_onIndicateurChanged(newValue);
},
items: state.indicateurs?.isNotEmpty == true
? state.indicateurs
.map((CodeDescriptionModel model) => DropdownMenuItem(value: model.code, child: Text(model.description)))
.toList()
: const [],
validator: (value) {
if (value == null || value.isEmpty) {
return 'Entrer l\'indicateur s\'il vous plait';
}
return null;
},
),
SizedBox(height: 24.0),
txtSite,
DropdownButtonFormField<String>(
isExpanded: true,
hint: Text("Choisissez le site"),
value: state.site?.code ?? null,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
onChanged: (String newValue) {
_onSiteChanged(newValue);
},
items: state.sites?.isNotEmpty == true
? state.sites.map((CodeDescriptionModel model) => DropdownMenuItem(value: model.code, child: Text(model.description))).toList()
: const [],
validator: (value) {
if (value == null || value.isEmpty) {
return 'Entrer le site s\'il vous plait';
}
return null;
},
),
Padding(
padding: EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(24),
),
onPressed: () {
if (_formKey.currentState.validate()) {
widget.onSave(
fiche.id,
state.indicateur,
state.site?.code ?? null,
);
Navigator.pop(context);
}
},
padding: EdgeInsets.all(12),
color: Colors.blue,
child: Text('Create', style: TextStyle(color: Colors.white)),
),
)
],
),
),
);
},
);
}
}
感谢您的帮助
答案 0 :(得分:1)
您在onSaveCallback
中使用了错误的上下文。这是您的小部件的简化层次结构:
- MaterialApp
- EtatCollecteScreen
- MultiBlocProvider
- FicheMvtAddScreen
因此,在您的onSaveCallback
中,您正在访问FicheMvtAddScreen
的上下文,从上面的层次结构可以明显看出BlocProvider
找不到请求的Bloc
。很容易解决这个问题:
MaterialPageRoute(
builder: (pageContext) {
return FicheMvtAddScreen(onSaveCallback: (idFiche, indicateurModel, codeSite) {
BlocProvider.of<FicheMvtBloc>(context).add(
FicheMvtAdded(
idFiche: idFiche,
indicateurModel: indicateurModel,
codeSite: codeSite,
),
);
});
},
settings: RouteSettings(
arguments: ficheModel,
),
),
我在路由生成器函数中将上下文变量重命名为pageContext
(这样就不会遮盖所需的上下文)。现在BlocProvider
应该可以通过访问正确的上下文来找到请求的Bloc
。
另一种解决方法是将MultiBlocProvider
放在小部件层次结构中较高的位置。