Home > Software design >  List remains empty after adding elements in flutter firebase
List remains empty after adding elements in flutter firebase

Time:08-29

I have tried to add session model to a list of sessions like this but the list reamains empty. My database has the following structure I'm looping two refernces to get into the session timestamps

void getData()
{
    var Ref = fb.ref("sessions");
    Ref.onValue.listen((event){
      var snapshot = event.snapshot;
      Iterable<DataSnapshot> children = snapshot.children;
      for( var k in children)
        {
          var ref = fb.ref("sessions/${k.key}");
          ref.onValue.listen((event) {
            var snp = event.snapshot;
            Iterable<DataSnapshot> chi = snp.children;
            for(var v in chi)
              {
                Session s = new Session();
                s.timeStamp = v.key.toString();
                s.date = k.key.toString();
                s.session = v.value.toString();
                sessions.add(s);
              }
          });
        }
      sessions.refresh();
      print(sessions);
      totalsessions.value = sessions.length;
    });
  }

Output

I/flutter (11551): []

CodePudding user response:

Data is loaded from Firebase (and most modern cloud APIs) asynchronously, and while that is going on your main code continues to execute.

It's easiest to see this if you run in a debugger or add some logging statements like this:

var ref = fb.ref("sessions");
print("Before attaching first onValue");
ref.onValue.listen((event) {
  print("In first onValue");
  var snapshot = event.snapshot;
  Iterable<DataSnapshot> children = snapshot.children;
  for( var k in children) {
    var ref = fb.ref("sessions/${k.key}");
    ref.onValue.listen((event) {
      print("In second onValue");
    });
  }
  print("After second onValue");
});
print("After first onValue");

When you run this code, it prints:

Before first onValue

After first onValue

In first onValue

After second onValue

In second onValue

This may not be what you expect, but it does explain why your sessions is empty when you print it. By the time your print(sessions) runs, the sessions.add(s) hasn't happened yet.


This problem is incredibly common, and the solution is always the same: any code that needs the data from the database has to be inside the callback that runs when that data is available.

So:

var ref = fb.ref("sessions");
ref.onValue.listen((event){
  var snapshot = event.snapshot;
  Iterable<DataSnapshot> children = snapshot.children;
  for(var k in children) {
    var ref = fb.ref("sessions/${k.key}");
    ref.onValue.listen((event) {
      var snp = event.snapshot;
      Iterable<DataSnapshot> chi = snp.children;
      for(var v in chi) {
        Session s = new Session();
        s.timeStamp = v.key.toString();
        s.date = k.key.toString();
        s.session = v.value.toString();
        sessions.add(s);
      }
      sessions.refresh();
      print(sessions);
      totalsessions.value = sessions.length;
    });
  }
});

In your case though, we can simplify the code a lot further. Since you get a read sessions, the snapshot you get contains all data under that path in the database. So you don't need additional listeners to get each specific sessions, but can get the data from the children.

Something like:

var ref = fb.ref("sessions");
ref.onValue.listen((event){
  var snapshot = event.snapshot;
  Iterable<DataSnapshot> children = snapshot.children;
  for(var child in children) {
    Iterable<DataSnapshot> grandchildren = child.children;
    for(var grandchild in grandchildren) {
      Session s = new Session();
      s.timeStamp = grandchild.key.toString();
      s.date = child.key.toString();
      s.session = grandchild.value.toString();
      sessions.add(s);
    }
    sessions.refresh();
    print(sessions);
    totalsessions.value = sessions.length;
  }
});
  • Related