I would like to create an Object using data from my Firebase database. I get the data correctly, but I can't create that Objet in the way im trying. I have no idea why it doesn't work, this is my first time using Dart.
Here is my code
MaterialQR selectFromFirebase(String document) {
MaterialQR res = MaterialQR(exercises: [], image: '', name: '', id: '');
FirebaseFirestore.instance.collection('MaterialQR')
.doc(document).get()
.then((value) => res = new MaterialQR(
exercises: value['exercises'],
image: value['image'],
name: value['name'],
id: value['id']));
return res;
}
The objective is return an "empty" Object if the document in my database doesn't exist or return a correct Object if the document exists. When I print(value['id'])
inside .then()
, I got a correct id, but it doesn't work when I create the new Object.
CodePudding user response:
This is because data is loaded from Firestore (and pretty much any modern cloud API) asynchronously, because it may take some time before it's available. Instead of blocking your code (and the user) during this time, your main code actually continues to execute. Then when the data is available, your then
block executes.
This is easiest to see if you place some logging in the code, run it, and check its output.
print('Before starting to read from the database');
FirebaseFirestore.instance.collection('MaterialQR')
.doc(document).get()
.then((value) => {
print('got data from the database');
});
print('After starting to read from the database');
The output of this is:
Before starting to read from the database
After starting to read from the database
Got data from the database
This is probably not what you expected, but it explains perfectly why you don't get a result from selectFromFirebase
: the return res
runs before res
is ever set by your then
block.
There is no way to prevent this asynchronous nature of the call. Instead you'll have to accept that calling cloud APIs is asynchronous, and return a Future
from the method and mark is as async
:
Future<MaterialQR> selectFromFirebase(String document) async {
That also means you can use await
in there, so the entire function then becomes:
Future<MaterialQR> selectFromFirebase(String document) async {
try {
var value = await FirebaseFirestore.instance.collection('MaterialQR')
.doc(document).get();
return MaterialQR(
exercises: value['exercises'],
image: value['image'],
name: value['name'],
id: value['id']);
}
catch {
return MaterialQR(exercises: [], image: '', name: '', id: '');
}
}
See also:
- The Flutter documentation on asynchronous operations and futures
- The Flutter codelab on Asynchronous programming: futures, async, await.