云 Firestore 中的时间字段 serverTimestamp() 在第一个快照上返回 null [英] Time Field serverTimestamp() in cloud Firestore returns null on the first snapshot
问题描述
我正在从 Cloud Firestore 读取一些数据(消息),并且在文档中我有一个 timestamp
字段来表示时间.我有一个流:
Im reading some data(messages) from Cloud Firestore and in a document i have a timestamp
field for time.
I have a Stream:
Stream<QuerySnapshot> get chats {
return chatCollection.document(roomid).collection("messages").snapshots();
}
用于在我的数据库中发生更新时获取消息(例如新消息).
for getting the messages if a an update occurs in my database (ex New message).
所以当我启动应用程序时,它会从数据库中读取所有数据(消息)并将它们打印到我的应用程序中.这是我每次获得新快照时控制台打印消息的内容:
So when i start the app it reads all the data(messages) from the DB and i print them in my app. Here is what my console printing the messages every time i get a new snapshot:
D/ViewRootImpl@a0e5145[MainActivity]( 3045): MSG_RESIZED: frame=Rect(0, 0 - 1440, 2560) ci=Rect(0, 96 - 0, 1164) vi=Rect(0, 96 - 0, 1164) or=1
D/ViewRootImpl@a0e5145[MainActivity]( 3045): Relayout returned: old=[0,0][1440,2560] new=[0,0][1440,2560] result=0x1 surface={valid=true 492514541568} changed=false
I/flutter ( 3045): DEBUG: TEST-MESSAGE what??? 2020-10-09 22:30:12.249
I/flutter ( 3045): DEBUG: TEST-MESSAGE λολ 2020-10-09 21:59:58.212
I/flutter ( 3045): DEBUG: TEST-MESSAGE gamieste 2020-10-09 22:33:10.902
I/flutter ( 3045): DEBUG: TEST-MESSAGE holly 2020-10-09 22:26:39.672
I/flutter ( 3045): DEBUG: TEST-MESSAGE γφ 2020-10-09 22:08:47.617
I/flutter ( 3045): DEBUG: TEST-MESSAGE ελα 2020-10-09 22:13:38.167
I/flutter ( 3045): DEBUG: TEST-MESSAGE see re 2020-10-09 22:29:14.277
I/flutter ( 3045): DEBUG: TEST-MESSAGE ιξι 2020-10-09 22:10:07.442
I/flutter ( 3045): DEBUG: TEST-MESSAGE ολα καλα ρε 2020-10-09 22:05:00.703
I/flutter ( 3045): DEBUG: TEST-MESSAGE what??? 2020-10-09 22:30:12.249
I/flutter ( 3045): DEBUG: TEST-MESSAGE λολ 2020-10-09 21:59:58.212
I/flutter ( 3045): DEBUG: TEST-MESSAGE gamieste 2020-10-09 22:33:10.902
I/flutter ( 3045): DEBUG: TEST-MESSAGE holly fuck 2020-10-09 22:26:39.672
I/flutter ( 3045): DEBUG: TEST-MESSAGE γφ 2020-10-09 22:08:47.617
I/flutter ( 3045): DEBUG: TEST-MESSAGE ελα μου 2020-10-09 22:13:38.167
所以这没有问题.当我从我的代码中在我的数据库中添加一个新文档(消息)时,就会出现问题,然后它立即从数据库中获取更新,并且我拥有带有新消息列表的新快照.但是大约 0.5 秒我在屏幕上出现错误哦,我的 android,然后它变得正常并正确加载了所有消息.错误是文档特定字段的空指针.时间.时间是我的 Cloud Firestore DB 中的时间戳字段.
So no problem on that. The problem occurs when i add a new document(message) in my DB from my code, then immediately it gets the update from the DB and i have the new snapshot with the new list of messages. But for about 0.5 sec i get an error on the screen oh my android and then it gets normal and has loaded all messages correctly. The error is a null pointer for a specific field of the document. TIME. Time is timestamp field in 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)
您会看到它只是一个空异常.问题是为什么我只有在我上传消息时才会为时间字段获取空值.问题是,在那之后,消息再次来自另一个具有 no-null value 的快照!如果您查看错误代码段,我已经打印了整个对象,并且在右上角您会看到 时间字段具有空值.当时间字段为空时,我做了一个 if 语句来打印整个对象.
You will see that its just a null exception. The thing is why im getting a null for a Time field only when i upload a message. And the thing is that after that the message comes again from another snapshot with no-null value!! If you look on the error code segment i have printed the whole object and in the top right corner you will see that time field has null value. I made an if statement to print the whole object whenever time field is null.
所以最后我认为造成这种情况的原因是时间字段是一个时间戳,当我上传数据时,我给它一个 ServerTimestamp()
的值.代码在这里:
So at last the thing i think is causing this is that time field is a timestamp and when i upload the data i give it a value of ServerTimestamp()
.
Code here:
Future sendMessage(Message message) async {
if (message.senderId != AuthService.myUid) return null;
return await chatCollection.document(roomid).collection("messages").add({
"message": message.text,
"sender": message.senderId,
"receiver": message.receiverId,
"time": FieldValue.serverTimestamp(),
"isLiked": message.isLiked,
"unread": message.unread,
});
}
如您所见,Time 字段是唯一使用该 FieldValue.serverTimestamp()
的字段,所以我认为在时间戳值到字段时间之前,我以某种方式获取了文档的快照分配的.在我得到它之后(时间字段不为空)
As you can see the Time field is the only one that takes that FieldValue.serverTimestamp()
, so i think that somehow i get snapshot of the document before the Timestamp value to field time has been assigned. And after i get it all (with the Time field being no-Null)
有什么想法吗?
推荐答案
我也遇到了同样的问题.经过广泛搜索,我发现了这个 文章非常有用.它有助于理解问题和导致问题的流程.
I've also encountered the same problem. and after a wide search, I've found this article very useful. It helps to understand the issue and the flow causes the problem.
使用 DateTime.now()
不是解决方案,因为使用 FieldValue.serverTimestamp()
的主要目的是在不同设备之间同步时间,DateTime.now()
没有解决.
Using DateTime.now()
is not a solution since the main purpose of using the FieldValue.serverTimestamp()
is to sync times between different devices, which DateTime.now()
does not solves.
现在,关于 FieldValue 的 NULL 问题:我还按照建议使用了 sortTime.toDate().toString()
这里 ,但在时间戳上得到 NULL,因为:
now, regarding the NULL issue with the FieldValue:
I've also used sortTime.toDate().toString()
as suggested Here , but getting NULL on the timeStamp, because:
- 发送消息时,向服务器发送写请求,但数据尚不可用.
- builder 正在尝试提取数据并获得 null.
- 数据可用,NULL 替换为真实数据.为了解决那几毫秒的故障,我尝试了多种解决方案,但发现这个最简单:输入一个空字符串,直到该数据可用,UI 将空出大约 0.5 秒,但根据我的经验,它仍然看起来不错.
TL:DR
final sortTime = snapshot.data.documents[index].data()["sortTime"];
String serverTime = sortTime == null ? "" : sortTime.toDate().toString();
将此 Dart 代码视为一个简短的示例来解释:
consider this Dart code as a brief example to explain with:
发送消息功能:
/// 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);
}
);
}
},
);
}
这篇关于云 Firestore 中的时间字段 serverTimestamp() 在第一个快照上返回 null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!