I am using flutter and I have a simple method that reads each user present in my database and adds them to a list, once finished reading the users, the method must return the list containing all the data read, my problem is that my function does not wait that the Listener has finished reading and then returns my list (myList) even before the Listener has finished reading. How can I wait for the return myList until the Listener has read all the elements?
Here's the code:
Future<List<String>> getUsers () async {
List<String> myList = [];
final mRef = FirebaseDatabase.instance.ref().child("Users");
mRef.onValue.listen((event) async {
for (final child in event.snapshot.children) {
myList.add( child.value.toString() ); //ADDS THE VALUE TO THE LIST
}
});
//RETURN THE LIST
return myList;
}
I tried to put an await in front of my Listener but nothing worked.
CodePudding user response:
A listener is something that waits for changes (new documents added etc.) and notifies you whenever that happens. So it isn't something that starts/ends after you call it - you typically create it in the init of your Flutter class, and it changes state whenever something changes.
It looks like you want to grab all the users, once, and not listen like you're currently doing.
So instead of listening, perhaps just read the data. Something like:
// fetch all the documents
final allDocs =
await FirebaseFirestore.instance.collection('users').get();
// map them to something like your strings.
final thedetails = allDocs.docs.map((DocumentSnapshot e) => e.data()!.toString()).toList();
return thedetails;
CodePudding user response:
A really good way to learn and understand how Firebase works with flutter is FlutterFire, as you are dealing with future result you should use any state management to control at first if it is complete or not and then consider that return a promise and the way you manage that is different. This is an example for Future use as described in FlutterFire Cloud Firestore documentation:
class GetUserName extends StatelessWidget {
final String documentId;
GetUserName(this.documentId);
@override
Widget build(BuildContext context) {
CollectionReference users = FirebaseFirestore.instance.collection('users');
return FutureBuilder<DocumentSnapshot>(
future: users.doc(documentId).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {
return Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>;
return Text("Full Name: ${data['full_name']} ${data['last_name']}");
}
return Text("loading");
},
);
}
}
But if you just need to load once in a sync way the answer from Jon Mountjoy is the right one.