flutter - 如何为到达页面后的窗口小部件树中的所有窗口小部件提供身份验证证书,并使导航器仍在工作

标签 flutter dart

我正在构建一个要检查用户是否已登录的应用程序,否则,我将构建某个小部件树。因此,如果用户的身份验证状态更改,它将重建整个树。因此,您登陆到启动页面,启动页面一直等到它知道您是否已登录,然后返回RegisterPage或GroupManagementPage,这基本上是一个页面,您可以在其中看到所有组,有点像whatsapp,但没有对话,而是有组。问题是我只是不知道如何正确执行此操作。

我正在使用Firebase身份验证,当前要做的是从主应用程序外部始终提供AuthenticationProvider。在我的初始页面中,我在流构建器中使用此提供程序的流(从firebase基本上是onAuthChanged,但映射到AuthenticationCertificate),我等待流激活后再构建其余小部件树。如果流是 Activity 的,则将我的AuthenticationCertificate提供给GroupManagementPage。

这样就可以了,但是导航器出现了问题。因为在MainApp()中,我将初始页面定义为本地路线。因此,现在每当我弹出路线时,我都会回到初始页面,这不是我想要的。我还注意到有些页面没有提供AuthenticationCertificate。我不确定为什么会这样,因为导航器也传递了上下文,但仍必须调查一下。

现在我的问题是如何使它正常工作,以便将AuthenticationCertificate传递给从GroupManagementPage导航到的所有小部件,并且当用户注销时将其返回到RegisterPage?这是正确的方法,我该如何做呢?

主应用程序

return MultiProvider(
  providers: [
    ChangeNotifierProvider<PreferencesProvider>(
        create: (_) => PreferencesProvider()),
    Provider<AuthenticationProvider>(create: (_) => AuthenticationProvider(),),
    Provider<GroupProvider>(create: (_) => GroupProvider()),
    Provider<UserProvider>(
      create: (_) => UserProvider(),
    ),
  ],
  child: Consumer<PreferencesProvider>(
    builder: (context, preferences, _) => MaterialApp(
      home: TheSplashPage(),
      routes: <String, WidgetBuilder>{
        TheRegisterPage.routeName: (BuildContext context) =>
            TheRegisterPage(),
        TheGroupManagementPage.routeName: (BuildContext context) =>
            TheGroupManagementPage(),
        TheGroupPage.routeName: (BuildContext context) => TheGroupPage(),
        TheSettingsPage.routeName: (BuildContext context) =>
            TheSettingsPage(),
        TheProfilePage.routeName: (BuildContext context) =>
            TheProfilePage(),
        TheGroupCreationPage.routeName: (BuildContext context) =>
            TheGroupCreationPage(),
      },
      theme: preferences.isDarkMode
          ? DarkTheme.themeData
          : LightTheme.themeData,
      debugShowCheckedModeBanner: false,
    ),
  ),
);

启动画面
class TheSplashPage extends StatelessWidget {
  static const int loadTimeInSeconds = 2;

  @override
  Widget build(BuildContext context) {
    AuthenticationProvider authenticationProvider =
        Provider.of<AuthenticationProvider>(context);
    return FutureBuilder(
        future: Future.delayed(new Duration(seconds: loadTimeInSeconds)),
        builder: (context, delaySnapshot) {
          return StreamBuilder<UserAuthenticationCertificate>(
            stream: authenticationProvider.authenticationStream(),
            builder: (context, certificateSnapshot) {
              if (delaySnapshot.connectionState != ConnectionState.done &&
                  certificateSnapshot.connectionState ==
                      ConnectionState.active) {
                return Scaffold(
                  backgroundColor: Theme.of(context).backgroundColor,
                  body: Center(
                    child: Text(
                      'This is the splash page',
                      style: Theme.of(context).textTheme.body1,
                    ),
                  ),
                );
              } else {
                if (certificateSnapshot.hasData) {
                  return Provider<UserAuthenticationCertificate>.value(
                    value: certificateSnapshot.data, 
                    child: TheGroupManagementPage(),
                  );
                } else {
                  return TheRegisterPage();
                }
              }
            },
          );
        });
  }
}

身份验证提供程序中的流
  Stream<UserAuthenticationCertificate> authenticationStream()
  {
    return _authentication.onAuthStateChanged.map((firebaseUser) => UserAuthenticationCertificate.fromFirebase(firebaseUser));
  }

最佳答案

如果要使用Stream,请使用StreamProvider而不是Provider。但我不知道您为什么要在这种情况下使用Stream。为什么不选择ChangeNotifierProvider?

使用Navigator.of(context)导航到您的页面。您的代码的导航部分很奇怪。您在TheSplashPage()的构建函数中返回TheGroupManagementPage()或TheRegisterPage()。这不是导航器的工作方式。您应该使用Navigatort的方法,例如pushpoppushNamed等。

  Navigator.of(context).pushNamed(TheGroupManagementPage.routeName);

So now whenever I pop a route I go back to the splash page, which is not what I want.



登录后,可以从导航树中删除SplashPage。这是一种方法,不是一个坏方法。验证后推送页面时,应使用pushReplacementpushReplacementNamed。您也可以将其用于注销,以用RegisterPage()替换导航树。

或者,如果您有主屏幕(如启动后的根路由),则您的情况可能是TheGroupManagementPage。然后将 TheGroupManagementPage 包裹在 WillPopScope 中,然后在WillPop 的中进行操作。我更喜欢第一种方法。

关于flutter - 如何为到达页面后的窗口小部件树中的所有窗口小部件提供身份验证证书,并使导航器仍在工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60902932/

相关文章:

dart - Flutter 页面 View 不显示两张幻灯片

android - Flutter:如何禁用 `showDatePicker` 中的过去日期?

flutter - 如何使用 Flutter 在 VSCode 上修复可自动修复的问题?

flutter - 如何在共享首选项中将对象保存在json数组中?

Flutter null 安全 - 参数类型 'Color?' 不能分配给参数类型 'Color'

flutter - 我们可以为三星电视构建 Flutter 应用程序吗?

function - Dart 编程语言中的函数和方法有什么区别?

flutter - "threads"在 Dart 中使用 Flutter for web

flutter - 虽然显示了floatActionButton,但该图为空

dart - 将泛型类中的 T 限制为实现某些接口(interface)的类型