如何创建一个可以通过访问 MaterialApp 上下文来监听所有页面的 BlocListener?
Posted
技术标签:
【中文标题】如何创建一个可以通过访问 MaterialApp 上下文来监听所有页面的 BlocListener?【英文标题】:How to create a BlocListener that can listen to all pages in flutter with access to MaterialApp context? 【发布时间】:2020-08-01 08:47:37 【问题描述】:我正在尝试创建一个BlocListener
,它能够侦听整个应用程序中的所有页面/路由,就像您如何访问整个应用程序中的Bloc
或Provider
(如果它们已定义)一样像下面的代码一样在根级别
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider<IdentityTokenProvider>(
create: (_) => IdentityTokenProvider(),
),
],
child: MultiBlocProvider(
providers: [
BlocProvider<AuthBloc>(
create: (_) => AuthBloc(),
),
],
child: MaterialApp(
debugShowCheckedModeBanner: AppConfig.DEBUGGABLE,
theme: ThemeData(
// fontFamily: CustomFontStyle.montserrat,
),
home: AuthListener(
child: Center(
child: const MainApp(),
),
),
),
),
),
);
如您所见,我有提供者、集团和一名听众。我在其他页面中访问集团和提供者没有问题。我的问题是身份验证侦听器。一旦我移动到不同的页面(通过删除堆栈),我就无法访问AuthListener
,因为它在MaterialApp
内。但是,在这种情况下,我需要将特定的侦听器 (AuthListener
) 放在 MaterialApp
内,因为它包含使用页面导航的代码(如果在小部件树的外部/上方完成实现,则该代码不起作用MaterialApp
),并使我们使用 MaterialApp
上下文来显示对话框。
我的页面路由实现删除了堆栈,这是失去对AuthListener
的访问的另一个原因
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => route),
(Route<dynamic> route) => false);
为什么在移动到其他页面时要删除路由/页面堆栈?
我专门在认证后使用这个。您真的不希望用户在登录后能够按返回按钮,并将用户重定向回登录页面,对吗?通常后退按钮应该在他们登录时隐藏/关闭应用程序。我的AuthListener
实现
class AuthListener extends StatefulWidget
final Widget child;
const AuthListener(Key key, @required this.child) : super(key: key);
@override
_AuthListenerState createState() => _AuthListenerState();
class _AuthListenerState extends State<AuthListener>
@override
Widget build(BuildContext context)
return BlocListener<AuthBloc, AuthState>(
listener: (context, state)
if (state is AuthAuthenticated)
PageRouterController.pushAndRemoveStack(context, const EcomPage());
else if (state is AuthUnauthenticated)
PageRouterController.pushAndRemoveStack(context, const LoginPage());
,
child: widget.child,
);
有没有其他方法可以解决这个问题?
【问题讨论】:
您是否尝试使用 Builder 小部件包装侦听器? 使用构建器小部件的目的是什么?那不是一个小部件,您可以在其中添加一些代码然后返回一个小部件吗? 如果我理解您的问题是您无法收听 AuthBloc,因为它在树中与 AuthBloc 处于同一级别,对吗? 据我了解,我也无法访问 AuthBloc(一旦我完成身份验证并移至其他页面),因为侦听器位于 MaterialApp 中。据我了解,我只能访问根级别的块、提供程序、侦听器(在 MaterialApp 之上定义)。这意味着我可以在登录页面访问 AuthListener,但是当我移动到不同的页面时。我无法访问它。 我正在尝试实现这个顺便说一句,因为我计划创建一个功能,当用户通过 FCM(仅有效负载)收到静默通知时强制注销用户。所以我需要 AuthListener 位于 MaterialApp 中,因为我需要它的上下文能够通过 MaterialPageRoute 更改路由/页面,以及显示对话框。但是,问题出现在我无法在不同页面访问它的地方,因为它必须在根级别才能在任何地方访问。 【参考方案1】:所以我最终定义了一个
static final GlobalKey<NavigatorState> navigatorKey = new GlobalKey();
并在我的 MaterialApp 中使用它
@override
Widget build(BuildContext context)
return MaterialApp(
debugShowCheckedModeBanner: App.DEBUGGABLE,
theme: ThemeData(
// fontFamily: CustomFontStyle.montserrat,
),
navigatorKey: App.navigatorKey,
home: Center(
child: const LoginPage(),
),
);
因此,每当我必须在 MaterialApp 之外的实现情况下进行导航(在我的情况下,通过在 MaterialApp 上方的根级别找到的 AuthListener),我可以通过导航
App.navigatorKey.currentState.pushAndRemoveUntil(
MaterialPageRoute(builder: (_) => route),
(Route<dynamic> route) => false);
这意味着我终于可以访问 MaterialApp 导航器和上下文,即使在 MaterialApp 之外的侦听器也允许我进行导航和显示对话框
【讨论】:
以上是关于如何创建一个可以通过访问 MaterialApp 上下文来监听所有页面的 BlocListener?的主要内容,如果未能解决你的问题,请参考以下文章
我可以用 Provider 包装 MaterialApp 小部件吗?
如何使用 Flutter 在 MaterialApp 中创建卡片