Reputation: 11
The function signInWithGoogle
calls the getUser
function to retrieve the user information from the Firestore Database and expects a User
as the return. Because this is a Firestore API call, the User
returned by getUser
is a Future
and getUser
is called with an await
.
In the getUser
function, the User
is populated as expected and verified with the debugPrint("new user schedule 0: " + i[0].toJson());
However in the signInWithGoogle
function, the User
is not received back from the Future<User>
, as seen in the null reference to schedule
when performing debugPrint("user schedule 0: " + u.schedule[0].toJson());
I have tried setting the return value in multiple ways (getUser
function), including instantiating a user class separately before setting it's values and returning it.
Future<User> getUser(_uid) async {
DocumentSnapshot qs = await Firestore.instance
.collection('users')
.document(_uid)
.get();
if (qs.exists) {
setState(() {
state.loadingStatus = "Getting User Information";
});
return new User(
schedule: await getRecipes(
Firestore.instance
.collection('users')
.document(_uid)
.collection('schedule')
).then((i) {
debugPrint("get schedule");
debugPrint("new user schedule 0: " + i[0].toJson());
}).catchError((error) {
debugPrint('Error: $error');
}),
favorites: await getRecipes(
Firestore.instance
.collection('users')
.document(_uid)
.collection('favorites')
).then((i) {debugPrint("get favorites");}).catchError((error) {
debugPrint('Error: $error');
}),
subscription: await getSubscription(_uid).then((i) {debugPrint("get subscription");}),
pantry: await getIngredientsList(
Firestore.instance
.collection('users')
.document(_uid)
.collection('pantry')
).then((i) {debugPrint("get pantry");}).catchError((error) {
debugPrint('Error: $error');
}),
shopping: await getIngredientsList(
Firestore.instance
.collection('users')
.document(_uid)
.collection('shopping')
).then((i) {debugPrint("get shopping list");}).catchError((error) {
debugPrint('Error: $error');
}),
preferences: await getPreferences(_uid).then((i) {debugPrint("get preferences");}),
);
}else {
setState(() {
state.loadingStatus = "Creating new User Information";
});
return User.newUser();
}
}
Future<Null> signInWithGoogle() async {
setState(() {
state.loadingStatus = "Signing in with Google";
});
if (googleAccount == null) {
// Start the sign-in process:
googleAccount = await googleSignIn.signIn();
}
FirebaseUser firebaseUser = await signIntoFirebase(googleAccount);
User user = await getUser(firebaseUser.uid);
debugPrint("user schedule 0: " + user.schedule[0].toJson());
setState(() {
state.isLoading = false;
state.loadingStatus = "";
state.user = firebaseUser;
state.userInfo = user;
});
}
I/flutter (17962): new user schedule 0: {Proper data is printed here...
I/flutter (17962): get favorites
I/flutter (17962): get subscription
I/flutter (17962): get pantry
I/flutter (17962): get shopping list
I/flutter (17962): get preferences
E/flutter (17962): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The method '[]' was called on null.
E/flutter (17962): Receiver: null
E/flutter (17962): Tried calling: [](0)
I expect to not receive a null reference error when printing the schedule[0]
from signInWithGoogle
when the same call to print schedule[0]
works in the getUser
function.
This is probably something stupid simple I am missing, but I cannot figure out what is happening after looking through my code for the past 3 hours.
If you need any further information, please let me know.
Upvotes: 1
Views: 98
Reputation: 10915
The problem is around here:
schedule: await getRecipes(
Firestore.instance
.collection('users')
.document(_uid)
.collection('schedule')
).then((i) {
debugPrint("get schedule");
debugPrint("new user schedule 0: " + i[0].toJson());
// this is a problem, there is no return!
}).catchError((error) {
debugPrint('Error: $error');
}),
This passes a null
to the schedule:
argument, which was not your intention. When you await someFuture.then(something)
you get out the return value from something
, which is null
in this case, not the resolved value of someFuture
.
This is one of the reasons we recommend not to mix async/await
with .then
Upvotes: 1
Reputation: 2304
I don't know if this is causing the issue but you're mixing Futures and async/awaits. You really only need one. This line:
User user = await getUser(firebaseUser.uid).then((u) {debugPrint("user schedule 0: " + u.schedule[0].toJson());});
...could be seen a little simpler as:
User user = await getUser(firebaseUser.uid);
print(user.schedule[0].toJson());
The async/await is returning a future. Placing a .then() callback with an async/await statement isn't necessary.
Upvotes: 0