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