Home > OS >  Flutter: Stream is not updating data automatically (only after hot reload)
Flutter: Stream is not updating data automatically (only after hot reload)

Time:10-30

Problem: Both of my streams from the code below do not update my UI automatically. So the new data is only fetched and displayed when I do a hot reload or a hot restart. I am trying to fetch the most recent messages from each chat room and display them to the user.

Question: How can I change my code to make the streams work properly? Or is there maybe a better solution to what I am doing below?

    import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:blabber_tech/services/auth.dart';
import 'package:blabber_tech/services/chat_services.dart';

class MyChatsScreen2 extends StatelessWidget {
  static const String id = "mychats2_screen";

  // get current user id
  String? userId = AuthService().getUserId();

  // Stream of all rooms of current user
  Stream getRoomsStream() async* {
    // get rooms of current user
    QuerySnapshot roomsSnapshot = await FirebaseFirestore.instance
        .collection("rooms")
        .where("userId1", isEqualTo: userId)
        .get();
    // get rooms of current user
    QuerySnapshot roomsSnapshot2 = await FirebaseFirestore.instance
        .collection("rooms")
        .where("userId2", isEqualTo: userId)
        .get();
    // add rooms of current user to rooms list
    List<QueryDocumentSnapshot> rooms = roomsSnapshot.docs;
    // add rooms of current user to rooms list
    List<QueryDocumentSnapshot> rooms2 = roomsSnapshot2.docs;
    // add rooms of current user to rooms list
    rooms.addAll(rooms2);
    // sort rooms list by when last message was sent
    // rooms.sort(
    // (a, b) => b["lastMessageSentAt"].compareTo(a["lastMessageSentAt"]));
    yield rooms;
  }

  // Stream to get last message of each room
  Stream getLastMessageStream(String roomId) async* {
    try {
      // get last message of room
      QuerySnapshot lastMessageSnapshot = await FirebaseFirestore.instance
          .collection("rooms")
          .doc(roomId)
          .collection("messages")
          .orderBy("createdAt", descending: true)
          .limit(1)
          .get();
      // get last message of room
      List lastMessage = lastMessageSnapshot.docs;
      // return last message of room
      yield lastMessage;
    } catch (error) {
      print(error);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        // create listview of all chats of current user and show last message and other user name and photo
        child: StreamBuilder(
          stream: getRoomsStream(),
          builder: (context, AsyncSnapshot<dynamic> snapshot) {
            if (snapshot.hasData) {
              return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (context, index) {
                  return StreamBuilder(
                    stream: getLastMessageStream(snapshot.data[index].id),
                    builder: (context, AsyncSnapshot<dynamic> snapshot2) {
                      if (snapshot2.hasData) {
                        return ListTile(
                          leading: CircleAvatar(
                              //backgroundImage: NetworkImage(
                              //snapshot.data[index]["userPhotoUrl"]),
                              ),
                          //title: Text(snapshot.data[index]["userName"]),
                          subtitle: Text(snapshot2.data[0]["message"]),
                        );
                      } else {
                        return Container();
                      }
                    },
                  );
                },
              );
            } else {
              return Container();
            }
          },
        ),
      ),
    );
  }
}

CodePudding user response:

Since you're using get() when the widget is created, the data is only loaded from the database once when the widget is created. If you want to get the new data whenever it is updated, use a snapshot() listener - which returns a stream which gets an initial event with the initial data, and a new event whenever the data is updated.

To wire the Stream up in your build method, you'll want to use a StreamBuilder as shown in the Firebase documentation on listening for realtime updates in Flutter.

  • Related