我正在使用Firebase Realtime数据库向我的应用程序添加聊天功能。在数据库中,我有以下数据:
{
events: {
"event-uuid1": {
"chat-uuid1": {
"message": "hey"
},
"chat-uuid2": {
"message": "hey again"
}
}
}
}
在我的Flutter应用程序中,我有这个StreamBuilder(我知道这是冗长的,我不知道问题在哪里,所以提供更多而不是更少):
class _EventChatScreenState extends ConsumerState<EventChatScreen> {
FirebaseDatabase dbInstance = FirebaseDatabase.instance;
late TextEditingController _messageFieldController;
late DatabaseReference eventDbRef;
@override
void initState() {
super.initState();
_messageFieldController = TextEditingController();
eventDbRef = dbInstance.ref("none");
}
@override
void dispose() {
_messageFieldController.dispose();
super.dispose();
}
Map<String, ChatMessage> chatMessages = {};
@override
Widget build(BuildContext context) {
final user = ref.watch(userProvider);
final event = ModalRoute.of(context)!.settings.arguments as EventRepository;
if (eventDbRef.path == "none") {
print("IT IS NONE");
eventDbRef = dbInstance.ref("/events/${event.event.eventId}/");
print(eventDbRef.path); // Print's correct value
}
return StreamBuilder(
stream: eventDbRef.onChildAdded,
builder: (context, snapshot) {
if (chatMessages == {}) {
return const Text("Loading...");
}
DatabaseEvent data;
if (snapshot.hasData) {
data = snapshot.data as DatabaseEvent;
ChatMessage newChatMessage = ChatMessage(
chatMessageId: "",
userId: "",
displayname: "",
message: "",
datetime: "",
);
for (var child in data.snapshot.children) {
switch (child.key) {
case "chatMessageId":
newChatMessage.chatMessageId = child.value.toString();
break;
case "userId":
newChatMessage.userId = child.value.toString();
break;
case "displayName":
newChatMessage.displayname = child.value.toString();
break;
case "message":
newChatMessage.message = child.value.toString();
break;
case "datetime":
final datetime = DateTime.parse(child.value.toString());
final DateFormat formatter = DateFormat('h:mm aa');
final String formatted = formatter.format(datetime);
newChatMessage.datetime = formatted;
break;
default:
}
}
if (chatMessages[data.snapshot.key] == null) {
chatMessages[data.snapshot.key!] = newChatMessage;
}
}
return ListView.builder(
itemCount: chatMessages.length,
itemBuilder: (context, index) {
String key = chatMessages.keys.elementAt(index);
if (chatMessages[key]!.userId == user.user.userId) {
return UnconstrainedBox(
alignment: Alignment.centerRight,
child: Container(
margin: const EdgeInsets.symmetric(vertical: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.only(left: 10),
child: Text(chatMessages[key]!.displayname),
),
Container(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 15),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
color: Theme.of(context).colorScheme.primary,
),
child: Text(chatMessages[key]!.message,
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
Container(
padding: const EdgeInsets.only(left: 10),
child: Text(chatMessages[key]!.datetime),
),
],
),
),
);
}
},
);
},
),
问题是,当用户进入聊天屏幕时,其中一条消息已经出现在聊天中。我希望没有任何消息,因为我没有在任何地方设置任何初始数据,没有使用实时数据库的持久性,也没有使用我自己的本地数据库。
我对StreamBuilders的理解是,它们只会在新数据进入时获取新数据,而不会获取可能已经存在的数据,因此不会通过它发送这些数据(也就是说,当一个新的聊天消息被发送时,流应该接收它,这是可行的,但是它不应该接收已经在数据库中的聊天消息).如果这种理解是错误的,那么为什么我只得到一个消息,尽管有2,3,4,等等?
也许我理解/使用StreamBuilders、Firebase实时数据库或两者都不正确?
2条答案
按热度按时间erhoui1w1#
也许你对streambuilder的理解是错误的。
假设您使用
FutureBuilder
,它会等到未来结束,然后相应地构建小部件,但如果您的数据库中发生更改,它不会再次构建,但对于StreamBuilder
,它基本上会侦听(并从流中获得初始数据,此处为db
)添加到流中并构建,每当它发生更改或向流中添加新数据(此处为database
)时,它将获取更新的数据并再次构建小部件。阅读此处:
https://firebase.flutter.dev/docs/firestore/usage/#realtime-changes
brccelvz2#
将这个
eventDbRef.onChildAdded
赋给initState中的一个变量,然后在streambuilder中使用这个变量作为流参数。在Streambuilder中调用db会导致每次构建小部件树时都重新运行它。