在构建MessageBubble(dirty)时引发了以下NoSuchMethodError:在null上调用了getter'millisecondsSinceEpoch'

时间:2020-08-18 19:10:17

标签: firebase flutter dart google-cloud-firestore flutter-layout

因此,我正在创建一个移动聊天应用程序(仅供学习)。我试图使其使用time_formatter包推送消息的时间戳(来自Firebase)以将其显示在屏幕上。它实际上正在工作,但是每次我发送一条消息时,仿真器屏幕都会变红约1秒钟,并抛出此错误:

════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building MessageBubble(dirty):
The getter 'millisecondsSinceEpoch' was called on null.
Receiver: null
Tried calling: millisecondsSinceEpoch

The relevant error-causing widget was: 
  MessageBubble file:///C:/Users/cauer/Desktop/Apps-Flutter/flash_chat_flutter/lib/screens/chat_screen.dart:141:33
When the exception was thrown, this was the stack: 
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1      MessageBubble.build (package:flash_chat/screens/chat_screen.dart:208:32)
#2      StatelessElement.build (package:flutter/src/widgets/framework.dart:4576:28)
#3      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4502:15)
#4      Element.rebuild (package:flutter/src/widgets/framework.dart:4218:5)

此后,它在屏幕上准确显示了我想要的内容,但是我确实想知道发生了什么并对其进行修复。对不起,我在这里知道。如果需要,我会发布更多代码或任何其他信息,但我可以肯定这是由此处的某些原因引起的。

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flash_chat/constants.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:time_formatter/time_formatter.dart';

final _firestore = Firestore.instance;
FirebaseUser loggedInUser;

class ChatScreen extends StatefulWidget {
  static String id = 'chat_screen';

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

class _ChatScreenState extends State<ChatScreen> {
  final messageTextController = TextEditingController();
  final _auth = FirebaseAuth.instance;
  String messageText;

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

      void getCurrentUser() async {
    try {
      final user = await _auth.currentUser();
      if (user != null) {
        loggedInUser = user;
      }
    } catch (e) {
      print(e);
    }
  }


  void messageStream() async {
    await for (var snapshot in _firestore.collection('messages').snapshots()) {
      for (var message in snapshot.documents) {
        print(message.data);
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: null,
        actions: <Widget>[
          IconButton(
              icon: Icon(Icons.close),
              onPressed: () {
                _auth.signOut();
                Navigator.pop(context);
              }),
        ],
        title: Text('⚡️Chat'),
        backgroundColor: Colors.lightBlueAccent,
      ),
      body: SafeArea(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            MessagesStream(),
            Container(
              decoration: kMessageContainerDecoration,
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  Expanded(
                    child: TextField(
                      controller: messageTextController,
                      onChanged: (value) {
                        messageText = value;
                      },
                      decoration: kMessageTextFieldDecoration,
                    ),
                  ),
                  FlatButton(
                    onPressed: () {
                      messageTextController.clear();
                      _firestore.collection('messages').add({
                        'text': messageText,
                        'sender': loggedInUser.email,
                        'timestamp': FieldValue.serverTimestamp(),
                      }).then((value) => print('${value.documentID} added'));
                      messageTextController.clear();
                    },
                    child: Text(
                      'Send',
                      style: kSendButtonTextStyle,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class MessagesStream extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: _firestore
          .collection('messages')
          .orderBy('timestamp', descending: false)
          .snapshots(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return Center(
            child: CircularProgressIndicator(
              backgroundColor: Colors.lightBlueAccent,
            ),
          );
        }
        final messages = snapshot.data.documents.reversed;
        List<MessageBubble> messageBubbles = [];
        for (var message in messages) {
          final messageText = message.data['text'];
          final messageSender = message.data['sender'];
          final messageTime = message.data['timestamp']; //add this

          final currentUser = loggedInUser.email;

          final messageBubble = MessageBubble(
            sender: messageSender,
            text: messageText,
            isMe: currentUser == messageSender,
            time: messageTime,
          );
          messageBubbles.add(messageBubble);
        }
        return Expanded(
          child: ListView(
            reverse: true,
            padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
            children: messageBubbles,
          ),
        );
      },
    );
  }
}

class MessageBubble extends StatelessWidget {
  MessageBubble({this.sender, this.text, this.isMe, this.time});

  final String sender;
  final String text;
  final bool isMe;
  final Timestamp time;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.all(10.0),
      child: Column(
        crossAxisAlignment:
            isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
        children: <Widget>[
          Text(
            '$sender',
            style: TextStyle(
              fontSize: 12.0,
              color: Colors.black54,
            ),
          ),
          Material(
            borderRadius: isMe
                ? BorderRadius.only(
                    topLeft: Radius.circular(30.0),
                    bottomLeft: Radius.circular(30.0),
                    bottomRight: Radius.circular(30.0))
                : BorderRadius.only(
                    topRight: Radius.circular(30.0),
                    bottomLeft: Radius.circular(30.0),
                    bottomRight: Radius.circular(30.0)),
            elevation: 5.0,
            color: isMe ? Colors.lightBlueAccent : Colors.white,
            child: Padding(
              padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 20.0),
              child: Text(
                '$text',
                style: TextStyle(
                  color: isMe ? Colors.white : Colors.black54,
                  fontSize: 15,
                ),
              ),
            ),
          ),
          Text(
            '${formatTime(time.millisecondsSinceEpoch)}',
            style: TextStyle(
              fontSize: 11.0,
              color: Colors.black54,
            ),
          ),
        ],
      ),
    );
  }
}

将不胜感激,已经在寻找答案但找不到答案。

This is what the screen displays in the moment that the message is sent

2 个答案:

答案 0 :(得分:2)

我认为这应该可行。

单独创建一个函数,以便您可以在时间为空的情况下进行处理。

Widget handleerr() async{
await Future.delayed(const Duration(milliseconds: 2000), () {



  setState(() {
   
Text(
            '${formatTime(time.millisecondsSinceEpoch)}',
            style: TextStyle(
              fontSize: 11.0,
              color: Colors.black54,
          )
  });

});

}

答案 1 :(得分:2)

如此修改MessageBubble构造函数

MessageBubble({this.sender, this.text, this.isMe, Timestamp time}):time = time ?? Timestamp.now();

问题是Firestore在本地写入数据时{​​{1}}为空