Cloud 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数据库中的时间戳记字段.
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)
您将看到它只是一个空异常.问题是为什么仅在我上载消息时,即时消息的时间字段为null.事实是,在此之后,该消息再次来自具有 no-null值的另一个快照!如果您查看错误代码段,我已经打印了整个对象,并且在右上角您将看到时间字段具有空值.我创建了一条if语句,以在时间字段为null时打印整个对象.
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,
});
}
如您所见,时间"字段是唯一使用该 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)
有什么想法吗?
推荐答案
我也遇到了同样的问题.在广泛搜索之后,我发现了这个 article 非常有用.它有助于理解问题,并由流程引起问题.
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.
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);
}
);
}
},
);
}
这篇关于Cloud Firestore中的时间字段serverTimestamp()在第一个快照上返回null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!