Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Firebase cloud Firestore中的时间字段serverTimestamp()在第一个快照上返回null_Firebase_Flutter_Google Cloud Firestore_Timestamp - Fatal编程技术网

Firebase cloud Firestore中的时间字段serverTimestamp()在第一个快照上返回null

Firebase cloud Firestore中的时间字段serverTimestamp()在第一个快照上返回null,firebase,flutter,google-cloud-firestore,timestamp,Firebase,Flutter,Google Cloud Firestore,Timestamp,我正在从CloudFireStore读取一些数据(消息),在一个文档中,我有一个时间戳字段。 我有一条小溪: Stream<QuerySnapshot> get chats { return chatCollection.document(roomid).collection("messages").snapshots(); } 所以没问题。当我从我的代码在我的数据库中添加一个新文档(消息)时,问题就出现了,然后它立即从数据库中得到了更新,我得到了带

我正在从CloudFireStore读取一些数据(消息),在一个文档中,我有一个时间戳字段。 我有一条小溪:

Stream<QuerySnapshot> get chats {
    return chatCollection.document(roomid).collection("messages").snapshots();
  }
所以没问题。当我从我的代码在我的数据库中添加一个新文档(消息)时,问题就出现了,然后它立即从数据库中得到了更新,我得到了带有新消息列表的新快照。但是在大约0.5秒的时间里,我的安卓系统屏幕上出现了一个错误,然后它恢复正常并正确加载了所有消息。该错误是文档特定字段的空指针时间。时间是my Cloud Firestore DB中的时间戳字段

下面是错误:

The following NoSuchMethodError was thrown building:
The method 'toDate' was called on null.
Receiver: null
Tried calling: toDate()

When the exception was thrown, this was the stack:
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1      _ChatScreenState._buildMessage (package:flutter_firebase_chat_app/screens/chat/chat_screen.dart:48:43)
#2      _ChatScreenState.build.<anonymous closure>.<anonymous closure> (package:flutter_firebase_chat_app/screens/chat/chat_screen.dart:226:40)
#3      SliverChildBuilderDelegate.build (package:flutter/src/widgets/sliver.dart:448:22)
#4      SliverMultiBoxAdaptorElement._build.<anonymous closure> (package:flutter/src/widgets/sliver.dart:1136:67)
#5      _HashMap.putIfAbsent (dart:collection-patch/collection_patch.dart:140:29)
#6      SliverMultiBoxAdaptorElement._build (package:flutter/src/widgets/sliver.dart:1136:26)
#7      SliverMultiBoxAdaptorElement.performRebuild.processElement (package:flutter/src/widgets/sliver.dart:1082:66) 
正如您所看到的,时间字段是唯一接受
FieldValue.serverTimestamp()
的字段,因此我认为在将时间戳值分配给字段Time之前,我以某种方式获得了文档的快照。在我得到所有信息后(时间字段不为空)


有什么想法吗?

您可以使用Dart中提供的DateTime模块添加数据,而不是使用FieldValue.serverTimestamp()

您可以使用DateTime.now()获取当前日期和时间,然后在从DB获取数据时,您可以根据需要对其进行格式化。我想这会解决你的问题


我也遇到了同样的问题。经过广泛的搜索,我发现这非常有用。 它有助于理解问题和导致问题的流程

使用
DateTime.now()
不是解决方案,因为主要目的是使用
FieldValue.serverTimestamp()
是在不同设备之间同步时间,这
DateTime.now()
无法解决

现在,关于FieldValue的NULL问题: 我还按照建议使用了
sortTime.toDate().toString()
,但时间戳上的值为NULL,因为:

  • 发送消息时,会向服务器发送写入请求,但数据还不可用
  • 生成器正在尝试提取数据,结果为空
  • 数据可用,空值替换为真实数据。 为了解决这几个毫秒的小故障,我尝试了多种解决方案,但发现这是最简单的: 在数据可用之前,输入一个空字符串,UI将为空大约0.5秒,但根据我的经验,它看起来仍然不错
  • TL:DR

    final sortTime = snapshot.data.documents[index].data()["sortTime"];
    String serverTime = sortTime == null ? "" : sortTime.toDate().toString();
    
    将此Dart代码作为一个简单的示例进行解释:

    发送消息功能:

    /// on pressed action (send to firebase, and show message)
    /// consider the messageController gets the input from the user
    sendMessage(MyUser myUser) async {
        if (messageController.text.isNotEmpty){
          Map<String, dynamic> chatMessage = {
            "senderUid" : myUser.userId,
            "text" : messageController.text,
            "sortTime" : FieldValue.serverTimestamp(),
          };
          messageController.text = "";
          await addConversationMessages(widget.chatRoomId, chatMessage);
        }
    }
    
    Future addConversationMessages(String chatRoomId, chatMessage) async {
      await chatsCollection
          .doc(chatRoomId)
          .collection("chats")
          .add(chatMessage);
    }
    
    
    小部件列表视图消息(MyUser MyUser){
    返回流生成器(
    流:聊天信息流,
    生成器:(上下文,快照){
    如果(!snapshot.hasData){
    返回中心(
    子对象:循环压缩机指示器(
    valueColor:AlwaysStoppedAnimation(颜色(0xFF087E8B)),
    )
    );
    }否则{
    返回ListView.builder(
    相反:是的,
    itemCount:snapshot.data.documents.length,
    itemBuilder:(上下文,索引){
    final msgText=snapshot.data.documents[index].data()[“text”];
    final msgUid=snapshot.data.documents[索引]
    .data()[“senderUid”];
    final sortTime=snapshot.data.documents[index].data()[“sortTime”];
    字符串serverTime=sortTime==null?”:sortTime.toDate().toString();
    返回消息(
    msgText、serverTime、msgUid);
    }
    );
    }
    },
    );
    }
    
    在堆栈溢出时,不显示代码和文本的图片。将文本复制到问题本身,并将其格式化,以便于阅读、复制和搜索。@DougStevenson我更改了最后一张照片的实际代码。实际上,所有图片都应该被复制的文本替换掉。这当然解决了问题。但是我不明白为什么serverTimestamp有这个问题!在我了解serverTimestamp()之前,我不会回答这篇文章。以下文档可能会回答您的问题:
    final sortTime = snapshot.data.documents[index].data()["sortTime"];
    String serverTime = sortTime == null ? "" : sortTime.toDate().toString();
    
    /// on pressed action (send to firebase, and show message)
    /// consider the messageController gets the input from the user
    sendMessage(MyUser myUser) async {
        if (messageController.text.isNotEmpty){
          Map<String, dynamic> chatMessage = {
            "senderUid" : myUser.userId,
            "text" : messageController.text,
            "sortTime" : FieldValue.serverTimestamp(),
          };
          messageController.text = "";
          await addConversationMessages(widget.chatRoomId, chatMessage);
        }
    }
    
    Future addConversationMessages(String chatRoomId, chatMessage) async {
      await chatsCollection
          .doc(chatRoomId)
          .collection("chats")
          .add(chatMessage);
    }
    
    
    getConversationMessages(String chatRoomId) async {
      return await chatsCollection
          .doc(chatRoomId)
          .collection("chats")
          .orderBy("sortTime", descending: true)
          .snapshots();
    }
    
    Stream chatMessagesStream;
    void initState(){
        getConversationMessages(widget.chatRoomId)
          .then((value){
            setState(() {
              chatMessagesStream = value;
            });
        });
        super.initState();
      }
    
    Widget ListViewMessages(MyUser myUser){
        return StreamBuilder(
            stream: chatMessagesStream,
            builder: (context, snapshot){
              if(!snapshot.hasData){
                return Center(
                    child: CircularProgressIndicator(
                      valueColor: AlwaysStoppedAnimation<Color>(Color(0xFF087E8B)),
                    )
                );
              } else {
                return ListView.builder(
                    reverse: true,
                    itemCount: snapshot.data.documents.length,
                    itemBuilder: (context, index) {
                      final msgText = snapshot.data.documents[index].data()["text"];
                      final msgUid = snapshot.data.documents[index]
                          .data()["senderUid"];
                      final sortTime = snapshot.data.documents[index].data()["sortTime"];
                      String serverTime = sortTime == null ? "" : sortTime.toDate().toString();
                      return _buildMessage(
                          msgText, serverTime, msgUid);
                    }
                );
              }
            },
        );
      }