【问题标题】:Getting Boolean State from Cloud_Firestore in dart从 dart 中的 Cloud_Firestore 获取布尔状态
【发布时间】:2021-01-06 09:37:26
【问题描述】:

我正在制作一个需要显示两个单独主页的应用,具体取决于我的 Cloud Firestore 数据库中的辅导员值是否等于 true。我是面向对象编程、dart 和 Firestore 的新手,所以请多多包涵。

我要做的是初始化一个名为counselor 的变量,并将其设置为等于我数据库中的counsoror 字段值。然后我希望首先检查用户是否已登录以及他们是否已签名,这就是我使用一系列 if 语句来查看辅导员布尔值是否等于真或假的时候。并根据结果显示某个主页。

我在我的应用程序上收到一条错误消息,提示我在我的辅导员小部件上返回空值。我怀疑这是因为我将咨询员变量设置为等于我的数据库中字段咨询员的名称,而不是实际的布尔值。问题是我不知道规避这个问题的语法。

这是我的代码

    import 'package:strength_together/models/user.dart';
import 'package:strength_together/Screens/authenticate/authenticate.dart';
import 'package:strength_together/Screens/home/home.dart';
import 'package:strength_together/Screens/home/wrapper.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:strength_together/services/database.dart';
import 'package:strength_together/Screens/home/counsHome.dart';

class Wrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final user = Provider.of<SUser>(context);
    bool counselor = getCounselor();
    //return either authenticate or home/couselor home
    if (user == null){
      return Authenticate();
    }else if(counselor == true){
    return CounselorHome();
    }else if(counselor == false){
    return Home();

    }
  }
}

// 数据库类

import 'package:cloud_firestore/cloud_firestore.dart';


class DatabaseService {

  final String uid;

  DatabaseService({this.uid});

  //collection reference
  final CollectionReference userCollection = FirebaseFirestore.instance
      .collection('User Data');

  Future updateUserData(String name, bool counselor) async {
    return await userCollection.doc(uid).set({
      'name': name,
      'Counselor': true,

    });
  }

  //get user data stream
  Stream<QuerySnapshot> get userData {
    return userCollection.snapshots();
  }

  Future<DocumentSnapshot> getDataSnapshotForCounselor() async
  {
    return await FirebaseFirestore.instance.collection('User Data')
        .doc(uid)
        .get();
  }

  bool getCounselorValue(DocumentSnapshot dataSnapshotForCounselor) {
    //modify this by passing proper keyValue to get counselor.
    return dataSnapshotForCounselor.data()['Counselor'];
  }
}

// 认证类

import 'package:firebase_auth/firebase_auth.dart';
import 'package:strength_together/Screens/authenticate/register.dart';
import 'package:strength_together/models/user.dart';
import 'package:strength_together/services/database.dart';
import 'package:flutter/material.dart';

class AuthService{

  final FirebaseAuth _auth = FirebaseAuth.instance;

  //instance of counselor
  bool _counselor;

  bool get counselor => counselor;

  void setCounselor(bool counselor) {
    _counselor = counselor;
  }

  //create user obj based on firebase user from my code
  SUser _userFromFirebaseUser(User user){
    return user != null ? SUser(uid: user.uid) : null;
  }

  //auth change user stream
  Stream<SUser> get user {
    return _auth.authStateChanges()
        .map(_userFromFirebaseUser);
  }

  //method to sign in anon
  Future signInAnon() async{
    try{
      UserCredential result = await _auth.signInAnonymously();
      User user = result.user;
      return _userFromFirebaseUser(user);
    }catch(e){
      print(e.toString());
      return null;
    }
  }

  //method to sign in with email/pass
  Future signInWithEmailAndPassword(String email, String password) async{
    try{
      UserCredential result = await _auth.signInWithEmailAndPassword(email: email, password: password);
      User user = result.user;
      return _userFromFirebaseUser(user);
    }catch(e){
      print(e.toString());
      return null;
    }
  }

  //method to register with email/pass
  Future registerWithEmailAndPassword(String email, String password) async{
    try{
      UserCredential result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
      User user = result.user;

      //create a new document for that user with the uid
      await DatabaseService(uid: user.uid).updateUserData('New user', _counselor);

      return _userFromFirebaseUser(user);
    }catch(e){
      print(e.toString());
      return null;
    }
  }

  //sign in with google

  //sign out
  Future signOut() async{
    try{
      return await _auth.signOut();
    }catch(e){
      print(e.toString());
      return null;
    }
  }

【问题讨论】:

    标签: firebase flutter dart google-cloud-firestore


    【解决方案1】:

    你的代码有很多问题。首先,您正在使用已弃用的 Firestore.instance 和 .document 。请改用FirebaseFirestore.instance 和FirebaseFirestore.instance.collection(...).doc(...)。

    来到您的代码,使用FutureBuilder 来决定要显示哪个页面,在决定时,您可以向用户显示CircularProgressIndicator。

    接下来,这段代码

    Firestore.instance.collection('User Data').document('Counselor');
    
    

    返回 DocumentReference 而不是所需的实际值。 所以在你得到DocumentReference 使用.get() 后,它返回一个Future&lt;DocumentSnapshot&gt;,DocumentSnapshot 类有一个方法data(),它返回Map&lt;String,dynamic&gt;。一旦你得到Map&lt;&gt;,你就可以简单地通过传递key值来获取你想要的数据。

    整个过程看起来像这样:

    Future<bool> getCounselorValue() async {
    
    return await FirebaseFirestore.instance.collection(...).doc(...).get().data()['keyvalue'];
    
    }
    

    再次,请记住您正在处理 Future,因此您必须使用 await 、 .then() 或 FutureBuilder 。我为您推荐FutureBuilder,如果您不确定如何使用它,请参考this。我还回答了this,如果您想动态决定首先向用户显示哪个页面(请参阅第一种方法),这可能会有所帮助。

    编辑:

    好的,所以我的代码有一个小错误。现在我与您分享更多代码,您可能会觉得有帮助。

    使您的类从无状态变为有状态并遵循以下代码:

    class Wrapper extends StatefulWidget{
    WrapperState createState()=> WrapperState();
    }
    
    class WrapperState extends State<Wrapper>
    { 
      Future<DocumentSnapshot> documentSnapshot;
      
      User getUser(BuildContext context)
      {
      return Provider.of<User>(context);
      }
    
      dynamic getStartingPage(bool counselor,User user)
    {
       if (user == null){
          return Authenticate();
        }else if(counselor == true){
          return CounselorHome();
        }else if(counselor == false){
          return Home();
    
      }
      }
      
     Future<DocumentSnapshot> getDocumentSnapshotForCounselor() async
     {
        return await FirebaseFirestore.instance.collection(...).doc(...).get();
     }
    
     bool getCounselorValue(DocumentSnapshot documentSnapshotForCounselor)
     {
        //modify this by passing proper keyValue to get counselor. 
       return  documentSnapshotForCounselor.data()['keyValue'];
     
     }
    
     @override
     void initState()
     {
      super.initState();
      documentSnapshot=getDocumentSnapshotForCounselor();
     
     }
     
     @override
     Widget build(BuildContext context) {
        return FutureBuilder(
          future:documentSnapshot,
          builder: (BuildContext ctx, AsyncSnapshot<dynamic> snapshot) {
            if (snapshot.connectionState != ConnectionState.done) {
              return Center( child : const CircularProgressIndicator());
            }
            else
              return getStartingPage(getCounselorValue(snapshot.data),getUser(context));
          }
        );
      }
     
    }
    
    
    

    修改getDocumentSnapshotForCounselor和getCounselorValue方法,可以从数据库中获取字段的值。 升级到最新版本的cloud_firestore ,访问this 了解如何操作和导入什么。

    编辑 2:

    当您登录用户时,通过电子邮件密码或使用谷歌登录等。它返回一个Future&lt;UserCredential&gt;,UserCredential 有一个属性user,它返回User。现在我们想要的是,我们可以使用 User.uid 获得用户的唯一 uid :

       UserCredential userCredential =await _auth.createUserWithEmailAndPassWord();
       
    String uid= userCredential.user.uid;
    
    

    现在使用这个 uid 在数据库中为用户创建一个条目:

    FirebaseFirestore.instance.collection("User Data").doc(uid).set({"Counselor":true,"name":name});
    
    

    然后,得到辅导员值,:

    
    FirebaseFirestore.instance.collection("User Data").doc(uid).get();
    
    and 
    
    documentSnapshotForCounselor.data()['Counselor'];
    
    

    以上代码仅作说明,请对您的代码进行适当修改。

    【讨论】:

    • 您觉得它有帮助吗?
    • 编辑了答案,如果您遇到一些错误,请告诉我。同时删除您之前的评论,公开您的电子邮件不是一个好主意。无论您对任何编码有什么疑问,都只在这里问。
    • 首先非常感谢您的帮助。我已经从我们的谈话中学到了很多。我将我的云 Firestore 版本更新为 14.0。不幸的是,我收到一条错误消息,提示“名称‘DataSnapshot’不是类型,因此不能用作类型参数。”另外,我在代码的其他区域中引用了此类,从无状态小部件到有状态小部件的更改会干扰吗?到目前为止,我收到了一个错误,但我认为那是数据快照错误造成的。再次感谢您的帮助。
    • 很抱歉再次出现错误,应该是 DocumentSnapshot,我不知道我是怎么错过的。无状态类具有不可变的字段,这意味着屏幕上呈现的任何内容都不会改变。但是在这里你动态决定显示哪个页面,同时还显示一个循环进度指示器,所以你必须使这个类有状态。而且我不认为 Sateful 会影响代码的其他部分。它只是意味着你在屏幕上的任何东西都可以改变。也不要忘记引用扩展 SatefulWidget 的第一个类。第二个应该标记为私有。
    • 也不要害怕报告错误。这就是这个论坛的运作方式。如果您发现答案有任何错误,请立即回复。很有可能给出答案的庇隆没有亲自测试过答案。老实说,并非在每种情况下都是可能的。因此有很大的错误空间。通过立即回复,你也表明你没有放弃这个问题,它鼓励这个人纠正他的答案。但这也不意味着你不应该做自己的研究
    猜你喜欢
    • 2021-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-25
    • 2016-07-08
    • 2012-02-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多