如何使streambuilder等待?

时间:2018-12-14 20:35:03

标签: firebase dart firebase-authentication flutter

我正在使用Firebase登录构建Flutter应用程序,但是在检查登录状态时遇到问题。在启动应用程序时,必须检查用户是否登录,以便可以显示正确的页面。如果登录显示首页(针对不同的用户角色)。如果没有,请显示登录页面。

我为此在应用程序的RootPage中使用streambuilder,但问题是应用程序必须首先通过Firestore db检查用户信息,以便它知道已登录的用户类型,然后才能路由至正确的页面。问题是我找不到让streambuilder在继续之前等待此功能检查用户信息的方法。因此,对由函数返回的值进行运算的条件不能正确评估。这是代码:

    body: new StreamBuilder<FirebaseUser>(
      stream: _auth.onAuthStateChanged,
      builder: (BuildContext context, snapshot)
      {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return new SplashScreen();
        }
        if (snapshot.hasData && getUserDetailsComplete == true) {
          _getUserDetails();

          if (isAdmin == true) {
            return new AdminScreen();
          } else if (isAdmin == false) {
            return new HomeScreen();
          }
        } else {
          return new RootPage();
        }
      },
    ),
  );
}

您现在可以通过以下方法解决此问题:1.在else语句中返回RootPage,使其循环执行,直到满足条件之一为止; 2.在函数_getUserDetails完成时将boolean设置为true,然后将其添加到条件中,以便小部件知道何时函数完成了。但这会使应用启动速度变慢,而且风格也不佳。

有人知道更好的方法吗?

谢谢大家!

2 个答案:

答案 0 :(得分:0)

您可以使用StatefulWidget。在窗口小部件的状态下,包括一个窗口小部件对象。在initState中,您可以存储一个占位符小部件(CircularProgressINnc等),然后调用一个在Firebase中进行某些检查的函数。确保此功能为async,因为它进行网络连接,这必须在单独的线程上完成。在此函数的最后,只需调用setState并将占位符小部件替换为所选的小部件。看起来像这样:

class MyScreen extends StatefulWidget {

  @override
  _MyScreenState createState() => _MyScreenState();
}

class _MyScreenState extends State<MyScreen> {
  Widget _screen;

  @override
  void initState() {
    _screen = CircularProgressIndicator();

    _doSomeFirebaseChecking();
  }

  void _doSomeFirebaseChecking() async {
    // Add your code that performs checks at Firebase here.

    // Then use setState to update the widget to a screen of choice.
    setState(() {
      if (isAdmin == true) {
        _screen = AdminScreen();
      } else if (isAdmin == false) {
        _screen = HomeScreen();
      }
    });
  }
}

在我编写的类似应用程序中,我不得不基于某些Web API的内容在屏幕上构建小部件。我使用了与此类似的方法,它的工作原理就像一种魅力。

我希望这会有所帮助!

答案 1 :(得分:0)

您可以使用 .then .getIdToken 来获取令牌和声明中的用户详细信息

Map<dynamic, dynamic> claims = {}; 
Auth.onAuthStateChanged.map((firebaseUser) {
  firebaseUser
      .getIdToken()
      .then((idTokenResult) => {
            if (idTokenResult.claims != null)
              {claims = idTokenResult.claims}
          })
      .catchError((e) => {print(e)});

有关使用自定义声明进行访问控制的更多信息:firebase Doc