【问题标题】:How to dispose of StreamBuilder value on sign out?如何在退出时处理 StreamBuilder 值?
【发布时间】:2021-10-04 14:23:31
【问题描述】:

我一直在尝试在登录时将用户配置文件检索到每个用户的帐户。每个用户的信息都存储在带有各自 uid 的文档中。

当用户注册并登录时,与该用户关联的数据正确显示。但是,当我创建第二个帐户并登录时,与第二个用户关联的数据会显示给用户 2 和用户 1。

如何处理 Streambuilder 中的值,以便每个登录用户都可以唯一地查看他们的个人资料?

下面是我的代码和我的数据库截图

FirebaseAuth _auth = FirebaseAuth.instance;
final uid = _auth.currentUser!.uid;
  final Stream<DocumentSnapshot<Map<String, dynamic>>> db = FirebaseFirestore
      .instance
      .collection('users')
      .doc(uid)
      .collection('Profile')
      .doc('Personal details')
      .snapshots();



                     Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text('First name'),
                        SizedBox(width: 40),
                        StreamBuilder<DocumentSnapshot>(
                          stream: db,
                          builder: (BuildContext context,
                              AsyncSnapshot<DocumentSnapshot> snapshot) {
                            if (snapshot.hasError)
                              return Text('Something went wrong');
                            if (snapshot.connectionState ==
                                ConnectionState.waiting)
                              return CircularProgressIndicator();

                            dynamic data = snapshot.data!.data();
                            return Text(data['First name']);
                            // return Text('First name', style: boldFont);
                          },
                        ),
                      ]),
                  Divider(color: Colors.black),
                  SizedBox(
                    height: 10,
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text('Last name'),
                      SizedBox(width: 40),
                      StreamBuilder<DocumentSnapshot>(
                        stream: db,
                        builder: (BuildContext context,
                            AsyncSnapshot<DocumentSnapshot> snapshot) {
                          if (snapshot.hasError)
                            return Text('Something went wrong');
                          if (snapshot.connectionState ==
                              ConnectionState.waiting)
                            return CircularProgressIndicator();

                          dynamic data = snapshot.data!.data();
                          return Text(data['Last name'], style: boldFont);
                          // return Text('Last name', style: boldFont);
                        },
                      ),
                    ],
                  ),

我的退出代码

onPressed: () async {
                        try {
                          await FirebaseAuth.instance.signOut();
                          errorMessage = '';
                        } on FirebaseAuthException catch (error) {
                          errorMessage = error.message!;
                        }
                        Navigator.of(context).pushReplacementNamed('/signIn');
                        setState(() {});
                      }

【问题讨论】:

  • 您能提供您当前的退出代码吗?
  • 嗨,维克多,我已经添加了退出代码

标签: firebase flutter google-cloud-firestore


【解决方案1】:

我认为需要StreamSubscription 来订阅来自Stream 的事件。 当用户登录成功时,您将在此subscription 上收听数据。当用户退出时,您将cancel 当前subscription。 示例:

_streamSubscriptionMessage = FirebaseDatabase.instance
        .reference()
        .child('users')
        .child(sl.get<AuthCubit>().getUid().toString())
        .child('badgeMessage')
        .onValue
        .map<int>((event) {
      try {
        return event.snapshot.value as int;
      } catch (error) {
        return 0;
      }
    })

【讨论】:

    【解决方案2】:

    您可以使用 StatefulWidget,添加一个状态变量来存储当前用户,使用它进行构建,并在 Firebase 身份验证状态更改时应用 setState

    User? _currentUser; // define in the widget's state class.
    
    @override Widget build(BuildContext context) {
      if (_currentUser == null) {
        // you can add something here
        return;
      }
      final Stream<DocumentSnapshot<Map<String, dynamic>>> db = 
      FirebaseFirestore
          .instance
          .collection('users')
          .doc(_currentUser.uid),
          .collection('Profile')
          .doc('Personal details')
          .snapshots();
      // rest of your build
    }
    

    并将其添加到您的 Firebase 身份验证侦听器或创建(如果您还没有):

    FirebaseAuth.instance.authStateChanges().listen((User? firebaseUser) {
      setState(() {
        _currentUser = firebaseUser;
      });
    });
    

    (最好在主应用层定义这个_currentUser,并使用ChangeNotifierProvider/Consumer/context.read等)

    【讨论】:

    • 嗨彼得,我还是个初学者,你规定的大部分内容我都无法成功实施,因为当你说“将状态变量添加到存储当前用户,使用它构建,并在 Firebase 身份验证状态更改时应用 setState'' 并且我没有 Firebase 身份验证侦听器
    【解决方案3】:

    如果发布的其他解决方案不成功,您可以尝试关注涉及 StreamBuilder 相关问题的this similar thread,并根据接受的答案使用ListView builderInheritedWidget。在这种情况下,setState() 方法会在每次数据发生变化时完全重建 ListView。

    请注意,这些文档是外部文档而非 GCP 官方文档,因此我无法保证其准确性。

    【讨论】:

    • 它对我不起作用
    • 我在此线程中阅读了您的其他评论,我建议您查看此tutorial 关于为用户登录实施 Firebase 身份验证。它专门使用 Streambuilder 来实现该功能。此外,here 是有关将 Firebase 身份验证与 Flutter 集成的文档。我不能保证任何外部 GCP 文档的准确性。
    猜你喜欢
    • 1970-01-01
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-16
    • 2022-11-17
    • 1970-01-01
    • 2013-09-12
    相关资源
    最近更新 更多