In my Android app, I have a database repository to contact Firebase Realtime Database and a service layer with some methods. My SaveUserProfile method works but I keep getting a null pointer on my GetUserFromUid.
The 'user' object it returns is null and I don't know why. The node in my DB is called "users" (all lowercase) and I want to retrieve a user as a model via their userId and display the name and email onscreen.
Can anybody see where I'm going wrong?
My DbContext:
public class DbContext implements IDbContext {
User user = null;
Context context;
DatabaseReference databaseUsers = FirebaseDatabase.getInstance().getReference("users");
public DbContext(Context context){
super();
this.context = context;
}
@Override
public void AddUserAccount(User user1) {
databaseUsers.child(user1.userId).setValue(user1);
}
@Override
public User GetUserFromFirebase(String uid) {
databaseUsers.child(uid)
.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
user = dataSnapshot.getValue(User.class);
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
return user;
}
My DbService:
public class DbService implements IDbService {
//instance of DbContext for firebase handling
private DbContext dbContext;
public DbService(Context context){
super();
dbContext = new DbContext(context);
}
@Override
public User SaveUserProfile(User u) {
dbContext.AddUserAccount(u);
return u;
}
@Override
public User GetUserFromUid(String uid) {
User user = dbContext.GetUserFromFirebase(uid);
return user;
}
My User model:
public class User {
public String userId;
public String name;
public String email;
public String account;
//constructor required for calls to DataSnapshot.getValue(User.class)
public User(){
}
public User(String userId, String name, String email, String account) {
this.userId = userId;
this.name = name;
this.email = email;
this.account = account;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
My activity where I want to display the users' details:
public class DetailsActivity extends AppCompatActivity {
//tag
private static final String TAG = DetailsActivity.class.getSimpleName();
//firebase auth
private FirebaseAuth mAuth;
//variables
private TextView inputName, inputEmail;
private DatabaseReference mFirebaseDatabase;
private String userId;
public String currentUserAccount;
public String teacherAccountNav = "Teacher";
public User userDetails;
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
inputName = findViewById(R.id.nameTextView);
inputEmail = findViewById(R.id.emailTextView);
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
assert user != null;
userId = user.getUid();
getUserDetails(userId);
inputName.setText(userDetails.name);
inputEmail.setText(userDetails.email);
}
public User getUserDetails(String uid){
DbService dbService = new DbService(this);
userDetails = dbService.GetUserFromUid(uid);
return userDetails;
}
EDITS BELOW
My callback:
public interface Callback {
void myResponseCallback(User user);
}
My EDITED DbContext:
public class DbContext implements IDbContext {
User user = null;
Context context;
DatabaseReference databaseUsers = FirebaseDatabase.getInstance().getReference("users");
public DbContext(Context context) {
this.context = context;
}
@Override
public void AddUserAccount(User user1) {
databaseUsers.child(user1.userId).setValue(user1);
}
@Override
public void GetUserFromFirebase(String uid, final Callback callback) {
databaseUsers.child(uid)
.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
user = dataSnapshot.getValue(User.class);
callback.myResponseCallback(user);
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
}
My EDITED DbService:
public class DbService implements IDbService {
//instance of DbContext for firebase handling
public DbContext dbContext;
public DbService(Context context){
super();
dbContext = new DbContext(context);
}
@Override
public User SaveUserProfile(User u) {
dbContext.AddUserAccount(u);
return u;
}
@Override
public User GetUserFromUid(String uid) {
final User[] user1 = {new User()};
dbContext.GetUserFromFirebase(uid, new Callback() {
@Override
public void myResponseCallback(User user) {
user1[0] = user;
}
});
return user1[0];
}
My EDITED Activity:
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
inputName = findViewById(R.id.nameTextView);
inputEmail = findViewById(R.id.emailTextView);
FirebaseDatabase mFirebaseInstance = FirebaseDatabase.getInstance();
//reference to 'users' node
mFirebaseDatabase = mFirebaseInstance.getReference("users");
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
assert user != null;
userId = user.getUid();
getUserFromFirebase(userId);
}
public void getUserFromFirebase(String uid){
userDetails = (new DbService(this)).GetUserFromUid(uid);
inputEmail.setText(userDetails.email);
inputName.setText(userDetails.name);
}
Debug BEFORE edits:

Debug AFTER edits:

As you can see from the debug, before the callback interface, userDetails was null. After the interface implementation, userDetails is not null but all of the object values are null. I don't know why this is as they are filled in the database. Any ideas?