firebase StreamBuilder在不应包含数据时包含数据

67up9zun  于 2022-12-04  发布在  其他
关注(0)|答案(2)|浏览(134)

我正在使用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实时数据库或两者都不正确?

erhoui1w

erhoui1w1#

也许你对streambuilder的理解是错误的。
假设您使用FutureBuilder,它会等到未来结束,然后相应地构建小部件,但如果您的数据库中发生更改,它不会再次构建,但对于StreamBuilder,它基本上会侦听(并从流中获得初始数据,此处为db)添加到流中并构建,每当它发生更改或向流中添加新数据(此处为database)时,它将获取更新的数据并再次构建小部件。
阅读此处:
https://firebase.flutter.dev/docs/firestore/usage/#realtime-changes

brccelvz

brccelvz2#

将这个eventDbRef.onChildAdded赋给initState中的一个变量,然后在streambuilder中使用这个变量作为流参数。在Streambuilder中调用db会导致每次构建小部件树时都重新运行它。

相关问题