Curtis Conaway
Curtis Conaway

Reputation: 11

Future not being returned from await function as expected

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

Answers (2)

Nate Bosch
Nate Bosch

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

Adrian Murray
Adrian Murray

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

Related Questions