StreamBuilder has data when it shouldn't

Garrett

I'm using Firebase Realtime database to add chat features to my app. In the database I have the following data:

{
    events: {
        "event-uuid1": {
            "chat-uuid1": {
                "message": "hey"
            },
            "chat-uuid2": {
                "message": "hey again"
            }
        }
    }
}

In my Flutter app, I have this StreamBuilder (I know this is lengthy, I'm not sure where the problem is so providing more rather than less):

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),
                            ),
                        ],
                    ),
                ),
            );
        }
    },
);
},
),

The problem is that when the user goes to the chat screen one of the messages will already be present in the chat. I would expect there to be nothing since I am not setting any initial data anywhere, not using Realtime Database's persistence, and not using my own local database yet.

My understanding of StreamBuilders is that they only get new data as it comes in, not data that may already exist and is thus not sent through it (Ie. when a new chat message is sent the stream should receive it, which works, but it should not receive chat message messages already in the database). If that understanding is wrong then why am I only getting one message despite there being 2, 3, 4, etc. in the database?

Perhaps I'm understanding/using StreamBuilders, Firebase Realtime Database, or both incorrectly?

GrahamD

Assign this eventDbRef.onChildAdded to a variable in initState and then use the variable as your stream parameter in streambuilder. Having the db call in Streambuilder causes it to be rerun everytime the widget tree builds.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related