Ben Carlson
Ben Carlson

Reputation: 762

Flutter - async function returns null

I've been working on this off and on for a couple of days now, and even after searching, and digging, haven't figured it out.

Here are the two relevant pieces of code:

Future<FirebaseUser> signUp(String email, String password, String username) async {
FirebaseUser user = await _firebaseAuth.createUserWithEmailAndPassword(
    email: email, password: password).then((newUser) {
      var obj = {
        "active": true,
        "public": true,
        "email": email,
        "username":username
      };
      _profileRef.child(newUser.uid).set(obj).then((_) {
        print("inside");
        //print("new userId: ${newUser}");
        //return newUser;
      });
});
//print("outside");
return user;
}

And:

Future<void> register() async {
final formState = _formKey.currentState;

if(formState.validate()) {
  formState.save();

  try {
    //print("email: " + _email + ", pwd: " + _password);
    //FirebaseUser user = await FirebaseAuth.instance.signInWithEmailAndPassword(email: _email,password: _password);
    //String uid = await widget.auth.signIn(_email, _password);
    FirebaseUser user = await widget.auth.signUp(_email, _password, _username);

    print("uid: " + user.uid);
    Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => HomePage(auth: widget.auth, userId: user.uid, onSignedOut: widget.onSignedIn,)));
    //Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => HomePage(auth: widget.auth, userId: uid, onSignedOut: widget.onSignedIn,)));
  } catch(e) {
    print(e);
  }
}
}

The signUp() function works properly, and correctly creates the user in Firebase, along with the userProfile entry in the Firebase realtime database. However, for whatever reason, I'm never able to get the actual FirebaseUser object back in the register() function. It always returns an error like the below:

    Connected Path: satisfied (Path is satisfied), interface: en0
Duration: 1.315s, DNS @0.001s took 0.004s, TCP @0.007s took 0.053s, TLS took 0.158s
bytes in/out: 5745/975, packets in/out: 9/9, rtt: 0.051s, retransmitted packets: 0, out-of-order packets: 0
[C3.1 8282B933-6D0B-4103-937C-173268FD0304 192.168.1.7:54700<->172.217.14.106:443]
Connected Path: satisfied (Path is satisfied), interface: en0
Duration: 0.441s, DNS @0.000s took 0.003s, TCP @0.005s took 0.054s, TLS took 0.152s
bytes in/out: 5040/1812, packets in/out: 9/9, rtt: 0.052s, retransmitted packets: 0, out-of-order packets: 0
flutter: NoSuchMethodError: The getter 'uid' was called on null.
Receiver: null
Tried calling: uid
flutter: inside

Upvotes: 0

Views: 2198

Answers (2)

Swift
Swift

Reputation: 3410

The problem is that chaining .then kind of "overrides" the previous promise's return type.

This function returns a Future<FirebaseUser> by itself:

_firebaseAuth.createUserWithEmailAndPassword(...);

However you have a .then chain that returns nothing which is why no value is assigned to the final result of the Future and it remains null:

.then((newUser) {
  var obj = {
    "active": true,
    "public": true,
    "email": email,
    "username":username
  };
  _profileRef.child(newUser.uid).set(obj).then((_) {
    print("inside");
  };
  // Need to return newUser here.
};

You can either add a return newUser;:

_profileRef.child(newUser.uid).set(obj).then((_) {
    print("inside");
};
return newUser;

or follow Richard's answer which gets rid of .then altogether and use await only instead which make your code look cleaner and easier to read especially when there is async chaining.

Upvotes: 1

Richard Heap
Richard Heap

Reputation: 51692

It's generally confusing to combine the use of await with then. Refactor your signUp method to remove the then.

Future<FirebaseUser> signUp(String email, String password, String username) async {
  FirebaseUser user = await _firebaseAuth.createUserWithEmailAndPassword(
    email: email, password: password);
  var obj = {
        "active": true,
        "public": true,
        "email": email,
        "username": username,
      };
  await _profileRef.child(user.uid).set(obj);
  return user;
}

Upvotes: 4

Related Questions