0

I'm trying to retreive a custom User object from Firebase as follows:

getUserFromDB(loggedInUserEmail);
viewModel = new ViewModelProvider(this).get(UserViewModel.class);
viewModel.sendUser(loggedInUser);

//...

public void getUserFromDB(String userEmail) {
    DocumentReference docRef = db.collection("users").document(userEmail);
    docRef.get().addOnSuccessListener(documentSnapshot -> {
        loggedInUser = documentSnapshot.toObject(User.class);

        Log.d("User Login", documentSnapshot.getId() + " => " + documentSnapshot.getData());
        Toast.makeText(MainActivity.this, "Login successful.", Toast.LENGTH_SHORT).show();
    });
}

However, the user being retreived always has null attributes. Here's a screenshot from when I was debugging.

Note: I made sure my User class has a public empty constructor and all the attributes have a getter method.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
Prescila
  • 21
  • 3

1 Answers1

2

Loading the user from the database is an asynchronous operation. While the data is being loaded, the main code continues and your viewModel.sendUser(loggedInUser) executes before the data is loaded. Then the success callback is fired and sets loggedInUser, but by that time the view model has already been initialized with the wrong value.

The rule is always quite simple: any code that needs data from the database, needs to be inside the success listener (or be called from there). So something like:

public void getUserFromDB(String userEmail) {
    DocumentReference docRef = db.collection("users").document(userEmail);
    docRef.get().addOnSuccessListener(documentSnapshot -> {
        loggedInUser = documentSnapshot.toObject(User.class);
        //  Initialize ViewModelProvider here
        viewModel = new ViewModelProvider(this).get(UserViewModel.class);
        viewModel.sendUser(loggedInUser);
    });
}

Also see:

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807