getter'uid'在null上被调用

时间:2020-04-02 11:13:58

标签: firebase flutter

伙计们,我有一个包含电子邮件和密码的登录页面,成功登录用户后,他会进入聊天屏幕。在聊天屏幕上,我需要访问用户uid以检查谁在发送消息,但是我收到“ getter'uid'在null上被调用”。我正在使用bloc模式登录验证程序。我该如何解决这种情况?

class LoginScreen extends StatefulWidget {
   FirebaseUser user;

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

   class _LoginScreenState extends State<LoginScreen> {

       final _loginBloc = LoginBloc();

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

       _loginBloc.outState.listen((state) async {
        switch (state) {
          case LoginState.SUCCESS:
            Navigator.of(context).pushReplacement(
               MaterialPageRoute(builder: (context) => ComercialUserScreen()));

            break;
            case LoginState.FAIL:
              showDialog(
           context: context,
           builder: (context) => AlertDialog(
                title: Text('Erro'),
                content: Text('Revise seu email e senha'),
              ));
         break;
       case LoginState.LOADING:
       case LoginState.IDLE:
      }
   });
  }

   @override
     Widget build(BuildContext context) {
      return Scaffold(
         body: StreamBuilder<LoginState>(
      stream: _loginBloc.outState,
      initialData: LoginState.LOADING,
      // ignore: missing_return
      builder: (context, snapshot) {
        print(snapshot.data);
        switch (snapshot.data) {
          case LoginState.LOADING:
            return Center(
              child: CircularProgressIndicator(),
            );
          case LoginState.FAIL:
          case LoginState.SUCCESS:
          case LoginState.IDLE:
            return Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: <Widget>[
                InputField(
                  icon: Icons.person_outline,
                  hint: 'Usuário',
                  obscure: false,
                  stream: _loginBloc.outEmail,
                  onChanged: _loginBloc.changeEmail,
                ),
                InputField(
                  icon: Icons.lock_outline,
                  hint: 'Senha',
                  obscure: true,
                  stream: _loginBloc.outEmail,
                  onChanged: _loginBloc.changePassword,
                ),
                SizedBox(
                  height: 32,
                ),
                StreamBuilder<bool>(
                    stream: _loginBloc.outSubmitValid,
                    builder: (context, snapshot) {
                      return RaisedButton(
                        child: Text("Entrar"),
                        onPressed:
                            snapshot.hasData ? _loginBloc.submit : null,
                      );
                    })
              ],
            );
        }
      }),
    );
   }
  }

 class LoginBloc extends BlocBase with LoginValidators{

    FirebaseUser _currentUser;

    final _emailController = BehaviorSubject<String>();
    final _passwordController = BehaviorSubject<String>();
    final _stateController = BehaviorSubject<LoginState>();

    Stream<String> get outEmail => _emailController.stream.transform(validateEmail);
    Stream<String> get outPassword =>_passwordController.stream.transform(validatePassword);
    Stream<LoginState> get outState => _stateController.stream;

    Stream<bool> get outSubmitValid => Observable.combineLatest2(
    outEmail, outPassword, (a, b) => true);

    Function(String) get changeEmail => _emailController.sink.add;
    Function(String) get changePassword => _passwordController.sink.add;

    StreamSubscription _streamSubscription;

    LoginBloc(){
        _streamSubscription = FirebaseAuth.instance.onAuthStateChanged.listen((user) async {
          if(user != null) {
            if(await verifyAdmins(user)) {
             _stateController.add(LoginState.SUCCESS);

        } else {
           FirebaseAuth.instance.signOut();
          _stateController.add(LoginState.FAIL);
        }

       } else {
         _stateController.add(LoginState.IDLE);
         }
      });
     }

     void submit (){
     final email = _emailController.value;
     final password = _passwordController.value;

      _stateController.add(LoginState.LOADING);

      FirebaseAuth.instance.signInWithEmailAndPassword(
      email: email,
      password: password
       ).catchError((e) {
      _stateController.add(LoginState.FAIL);
    });
  }

   Future<bool> verifyAdmins (FirebaseUser user) async {
    return await Firestore.instance.collection('users').document(user.uid).get().then((doc) 
    {
    if(doc.data != null){
     return true;
     } else {
      return false;
     }
    }).catchError((e) {
   return false;
  });
 }




@override
 void dispose() {
  _emailController.close();
  _passwordController.close();
  _stateController.close();

  _streamSubscription.cancel();
  // TODO: implement dispose
 }
}


 class _AdminChatState extends State<AdminChat> {

    bool _isLoading = false;

    void _sendMessage({String text, File imgFile}) async {

     DocumentSnapshot snapshot;

     FirebaseUser user = await FirebaseAuth.instance.currentUser();

     Map<String, dynamic> data = {
       "uid" : user.uid,
       'name' : user.displayName,
       'photo' : user.photoUrl,
       'time' : Timestamp.now()
      };

      if (imgFile != null){
         StorageUploadTask task = FirebaseStorage.instance.ref().child('users').child(
         DateTime.now().millisecondsSinceEpoch.toString()
       ).putFile(imgFile);

        setState(() {
        _isLoading = true;
         });

         StorageTaskSnapshot taskSnapshot = await task.onComplete;
         String url = await taskSnapshot.ref.getDownloadURL();
         data['imgUrl'] = url;

         setState(() {
          _isLoading = false;
         });
         }


      if(text != null) data["text"] = text;


       Firestore.instance.collection("users").document(snapshot.documentID)
       .collection('messages').add(data);

      }



     @override
      Widget build(BuildContext context) {
       return Scaffold(
         appBar: AppBar(
           title: Text('hello'),

         ),
          body: Column(
           children: <Widget>[
            Expanded(
             child: StreamBuilder<QuerySnapshot>(
               stream: 
       Firestore.instance.collection('users').document(widget.snapshot.documentID)
       .collection('messages').orderBy('time').snapshots(),
              builder: (context, snapshot){
               switch(snapshot.connectionState) {
                  case ConnectionState.none:
                  case ConnectionState.waiting:
                   return Center(
                     child: CircularProgressIndicator(),
                    );
                  default:
                    List<DocumentSnapshot> documents =
                    snapshot.data.documents.reversed.toList();

                return ListView.builder(
                    itemCount: documents.length,
                    reverse: true,
                    itemBuilder: (context, index){
                      // ignore: unrelated_type_equality_checks
                      return ChatMessage(documents[index].data, true);
                    });
            }
          },

          ),
         ),
      _isLoading ? LinearProgressIndicator() : Container(),
      TextComposer(_sendMessage),
    ],
   ),
  );
 }
 }

1 个答案:

答案 0 :(得分:0)

await FirebaseAuth.instance.currentUser();中的命令_AdminChatState不返回任何数据,因此,当您尝试根据用户插入数据时,该命令将返回null。发生这种情况是因为在未初始化状态时无法使用等待。如果发生这种情况,整个类将等待任何结果,直到返回用户为止。此外,您使用具有相同逻辑的存储查询。如果希望状态小部件在启动时运行某些程序,则可以使用initState()函数。如果要在等待数据返回FutureBuilderStreamBuilder的同时显示进度条,则是不错的选择。