使用showDialog()
导航到新上下文后,我尝试访问在应用程序根目录附近创建的bloc实例。但是,如果我像往常一样尝试通过从_thisBlocInstance = BlocProvider.of<ThisBlocType>(context)
之类的上下文中获取该块,则会得到一个错误,指示该上下文中没有提供块。
我认为这是因为showDialog()
构建器方法为对话框中的小部件分配了一个新上下文,这些小部件不知道我要查找的Bloc,该小部件在用户登录后立即实例化:
@override
Widget build(BuildContext context) {
_authBloc = BlocProvider.of<AuthBloc>(context);
_accountBloc = AccountBloc(authBloc: _authBloc);
return BlocProvider(
bloc: _accountBloc,
....
角落里有一个按钮,显示一个对话框:
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.all(18.0),
child: FloatingActionButton(
onPressed: () => showDialog(
context: context,
builder: (newContext) => EventDialog(),
).then(
(val) => print(val)
),
child: Icon(Icons.add),
),
),
);
}
然后在EventDialog中,尝试再次找到具有上下文的块:
@override
void build(BuildContext context) {
_accountBloc = BlocProvider.of<AccountBloc>(context);
_userMenuItems = _accountBloc.usersInAccount
.map((user) => DropdownMenuItem(
child: Text(user.userName),
value: user.userId,
))
.toList();
}
这失败了,并出现错误“ getter bloc被调用为null”,或者此上下文中没有该类型的bloc。
在使用showDialog()之后,是否有某种方法可以从上下文访问该块,或者导航到新的上下文?
这是集团供应商类:
import 'package:flutter/material.dart';
//This class is a generic bloc provider from https://www.didierboelens.com/2018/08/reactive-programming---streams---bloc/
//it allows easy access to the blocs by ancestor widgets and handles calling their dispose method
class BlocProvider<T extends BlocBase> extends StatefulWidget {
BlocProvider({
Key key,
@required this.child,
@required this.bloc,
}): super(key: key);
final T bloc;
final Widget child;
@override
_BlocProviderState<T> createState() => _BlocProviderState<T>();
static T of<T extends BlocBase>(BuildContext context){
final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context.ancestorWidgetOfExactType(type);
return provider.bloc;
}
static Type _typeOf<T>() => T;
}
class _BlocProviderState<T> extends State<BlocProvider<BlocBase>>{
@override
void dispose(){
widget.bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context){
return widget.child;
}
}
abstract class BlocBase {
void dispose();
}
答案 0 :(得分:2)
最后一个答案没问题,但可以简化,即只是将 Bloc 转移到其子小部件。
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.all(18.0),
child: FloatingActionButton(
onPressed: () => showDialog(
context: context,
builder: (newContext) => EventDialog((
accountBloc: BlocProvider.of<AccountBloc>(context),
),
).then(
(val) => print(val)
),
child: Icon(Icons.add),
),
),
);
}
class NewEventDialog extends StatelessWidget {
final AccountBloc accountBloc;
NewEventDialog({this.accountBloc}) : assert(accountBloc != null);
@override
void build(BuildContext context) {
_accountBloc = accountBloc;
_userMenuItems = _accountBloc.usersInAccount
.map((user) => DropdownMenuItem(
child: Text(user.userName),
value: user.userId,
))
.toList();
}
到目前为止,我发现通过页面路由转到小部件时会出现此问题。我们可以将 Bloc 小部件转移到小部件来避免这个问题。
答案 1 :(得分:1)
我发现在新上下文中访问原始块的最佳方法是将对它的引用传递给管理新上下文逻辑的新块。为了使代码保持模块化,每个块都不应控制超过一页的逻辑或一件事(例如用户的登录状态)。因此,当我使用showDialog()创建新的屏幕/上下文时,我还应该有一个新的块来处理该屏幕中的逻辑。如果需要引用原始块,则可以通过对话框窗口小部件的构造函数将其传递给新块的构造函数,因此,新块/上下文仍然可以访问原始块中的任何信息:
child: FloatingActionButton(
onPressed: () => showDialog(
context: context,
builder: (newContext) => NewEventDialog(
accountBloc: BlocProvider.of<AccountBloc>(context),
),
).then((event) => eventsBloc.addEvent(event)),
...
class NewEventDialog extends StatelessWidget {
final AccountBloc accountBloc;
NewEventBloc _newEventBloc;
NewEventDialog({this.accountBloc}) : assert(accountBloc != null);
@override
Widget build(BuildContext context) {
_newEventBloc = NewEventBloc(accountBloc: accountBloc);
return BlocProvider(
bloc: _newEventBloc,
...