0
votes

I try to implement the Firebase Realtime Database in Flutter and I want to display updated values in realtime. I try to achieve this with a StreamBuilder.

StreamBuilder Code

StreamBuilder(
  stream: GuestbooksDatabase().getAllGuestbooksSync().asStream(),
  builder: (context, snapshot) {
    if (!snapshot.hasData || !snapshot.data.length) {
      return CircularProgressIndicator();
    } else {
      return ListView.builder(
          shrinkWrap: true,
          itemCount: snapshot.data.length,
          itemBuilder: (context, index) {
            return Text(snapshot.data[index].title);
          });
    }
  }),

The stream function

Future<List<Guestbook>> getAllGuestbooksSync() async {
    List<Guestbook> guestbooks = [];
    databaseRef.onValue.listen((event) async {
      var dataSnapshot = event.snapshot;

      if (dataSnapshot.value != null) {
        dataSnapshot.value.forEach((key, value) async {
          Guestbook guestbook = await Guestbook.fromJson(value);
          guestbook.setId(key);
          guestbooks.add(guestbook);
        });

        await Future.delayed(Duration.zero);
        print(guestbooks); // Result: All Instances of Guestbook
        return guestbooks;
      }
    });
  }

I only see the CircularProgressIndicator() what means that the snapshot has no data. What's the issue there?

1
what does it mean !snapshot.data.length - Jitesh Mohite
Fires when the length of snapshot data is <= 0.. - asored
Did you check already which of the two conditions in snapshot.hasData || !snapshot.data.length is true? Because the latter means that the read completed, but resulted in no data, while the former means that the read never completed. Also: did you check the output of the app for errors/warnings? - Frank van Puffelen
If I print(snapshot.data) in the StreamBuilder the result is null. So there is no data and the !snapshot.hasData condition is true. - asored
PS: No errors, no warnings. From the getAllGuestbooksSync() I get the right output, but the StreamBuilder does not knows it... :/ - asored

1 Answers

0
votes

You can use StreamController for this.

Create a new controller -

final StreamController streamController = StreamController<List>.broadcast();

Convert Future<List> to void type for your getAllGuestbooksSync() function and return nothing.

It can and will be called in initState() -

void getAllGuestbooksSync() {
    List<Guestbook> guestbooks = [];
    databaseRef.onValue.listen((event) async {
      var dataSnapshot = event.snapshot;

      if (dataSnapshot.value != null) {
        dataSnapshot.value.forEach((key, value) async {
          Guestbook guestbook = await Guestbook.fromJson(value);
          guestbook.setId(key);
          guestbooks.add(guestbook);
        });

        print(guestbooks); // Result: All Instances of Guestbook

        streamController.add(guestbooks); // Adding list to the stream
      }
    });
}

In your StreamBuilder use -

stream: streamController.stream,