在 Flutter 的流构建器中使用 Future 构建器是正确的

Posted

技术标签:

【中文标题】在 Flutter 的流构建器中使用 Future 构建器是正确的【英文标题】:Is is correct to use Future builder inside a streambuilder in Flutter 【发布时间】:2020-11-26 22:34:31 【问题描述】:

我的要求是,每当用户使用电话号码进行验证时,它都会在 Firebase 中检查设置为用户电话号码的文档 ID(如果之前登录过)是否存在,如果存在则转到主页然后不会导航到 AccountVerification 页面。

另外,如果用户已经登录但没有验证关闭应用再打开应用,那么有两种情况,一种是用户验证了帐户详细信息,或者在验证过程中没有验证。在这种情况下,我将检查设置为用户电话号码的文档 ID 是否存在(如果存在),然后转到 HomePage 否则 AccountVerification 页面。 这是我的代码,它不能完美运行。任何人都可以建议我什么应该是正确的方法

void main() 
  runApp(MyApp());


class MyApp extends StatefulWidget 
  @override
  _MyAppState createState() => _MyAppState();


class _MyAppState extends State<MyApp> 

  var globalNumber;
  var Number;
  Firestore firestore = Firestore.instance;


  @override
  void initState() 
    // TODO: implement initState
    super.initState();
    getCurrentUser();



  

  @override
  Widget build(BuildContext context) 
    print(globalNumber);
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: StreamBuilder<Object>(
        stream: FirebaseAuth.instance.onAuthStateChanged,
          builder: (BuildContext context, snapshot) 
            if (snapshot.hasData) 
              return FutureBuilder(
                  future: Future.wait([

                    firestore.collection('users').document(globalNumber).get()

                  ]),
                  builder: (BuildContext context,
                      AsyncSnapshot<List> snapshot) 
                    DocumentSnapshot doc = snapshot.data[0];
                    if(snapshot.hasData) 
                      if (doc.exists) 
                        return HomePage();
                      
                      return AccountDetialsPage();
                    
                    else
                      return Container(child: Text('Loading'));
                    
                  
              );
             else 
              return Phoneverification();
            
          ),
    ) ;
  

  getCurrentUser() async

    final FirebaseAuth _auth = FirebaseAuth.instance;
    final FirebaseUser user = await _auth.currentUser();
    final uid = user.uid;
    globalNumber = user.phoneNumber;
    
    // Similarly we can get email as well
    //final uemail = user.email;
    print(uid);

  


【问题讨论】:

我的评论解决了你的问题吗?我正在寻找一些反馈,因为我刚开始在 *** 上帮助其他人! 您好,我已经将答案标记为正确......是的,它有帮助......非常感谢 【参考方案1】:

它不能正常工作,正如它所记录的那样:

“未来一定是更早获得的,例如在 State.initState、State.didUpdateConfig 或 State.didChangeDependencies 期间。在构造 FutureBuilder 时,不能在 State.build 或 StatelessWidget.buildmethod 调用期间创建它。如果 Future 与 FutureBuilder 是同时创建的,那么每次 FutureBuilder 的 parent 重建时,异步任务都会重新启动。”

这意味着当你的未来方法返回一个值时,会发生重建,触发另一个重建。这会创建一个循环。

您应该在initState() 上调用您的未来函数,然后使用该变量在构建方法中使用 FutureBuilder。例如:

    void main() 
      runApp(MyApp());
    

    class MyApp extends StatefulWidget 
      @override
      _MyAppState createState() => _MyAppState();
    

    class _MyAppState extends State<MyApp> 

      var globalNumber;
      var Number;
      var user;
      Firestore firestore = Firestore.instance;


      @override
      void initState()
         super.initState();
         getCurrentUser();
      


      Widget build(BuildContext context)
        return return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: StreamBuilder<Object>(
          stream: FirebaseAuth.instance.onAuthStateChanged,
          builder: (BuildContext context, snapshot) 
            if (snapshot.hasData) 
              return FutureBuilder(
                  future: user,
                  builder: (BuildContext context,
                      AsyncSnapshot<List> snapshot) 
                    DocumentSnapshot doc = snapshot.data[0];
                    if(snapshot.hasData) 
                      if (doc.exists) 
                        return HomePage();
                      
                      return AccountDetialsPage();
                    
                    else
                      return Container(child: Text('Loading'));
                    
                  
              );
             else 
              return Phoneverification();
            
        ),
      );
    

    getCurrentUser() async

      final FirebaseAuth _auth = FirebaseAuth.instance;
      final FirebaseUser user = await _auth.currentUser();
      final uid = user.uid;
      globalNumber = user.phoneNumber;
    
      // Similarly we can get email as well
      //final uemail = user.email;
      print(uid);
    
      getUserNumber(uid);
    

    //Make another function that you insert into the getCurrentUser(), like this:
    
    getUserNumber(int uid)
      user = Future.wait([
      firestore.collection('users').document(globalNumber).get()
    ]);
  

【讨论】:

我对 Flutter 完全不熟悉......你能告诉我代码吗......我被困在这个页面上 对不起,发布时没有进一步的代码编辑。看看这是否能解决您的问题。 @override void initState() super.initState(); x = Future.wait([ firestore.collection('users').document(globalNumber).get() ]); .... 这里当调用 init 函数时,我还没有 globalNumber,因为在我之前在 init 函数中的代码中,我调用了获取当前用户,然后从那里获取了用户号......如何解决我的意思是,当应用程序启动时,会调用 init 并且该数字尚未分配给 globalNumber 变量......另外,未来的“x”数据类型应该是什么?????? 更新了答案,以便您可以链接这两个事件。现在,您从 Future.await() 获得的值存储在一个类变量中。 类似于 user13891541:initState 不是异步函数。所以你的意思是在 initState 中获得未来并在构建期间提供未来?我意识到我想潜在地将提供未来的函数转换为 Stream,因为如果返回值发生变化,我希望状态发生变化

以上是关于在 Flutter 的流构建器中使用 Future 构建器是正确的的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Dart 中提供 Future<String> 来流式传输需要 String 的流? [复制]

如何在 Dart 的流构建器中切换我正在收听的流?

Flutter 流构建器概念

如何在 Flutter 中基于 Future 结果构建 Stream?

FLUTTER:如何在流构建器中使用导航器?

Flutter - 如何在流构建器中使用 await?