1

I was trying to work with Firebase Database. I get the data storing part but I cannot retrieve the data from the database and store it in a model class. The model class is below:

package com.joy.chat_two_point_o.models;

public class Users {
    private String uid,name,phoneNumber,profileImage,email,password;

    public Users(String uid, String name, String phoneNumber, String profileImage, String email, String password) {
        this.uid = uid;
        this.name = name;
        this.phoneNumber = phoneNumber;
        this.profileImage = profileImage;
        this.email = email;
        this.password = password;
    }

    public Users(String email, String password, String uid) {
        this.email = email;
        this.password = password;
        this.uid = uid;
    }

    public Users(String name, String profileImage) {
        this.name = name;
        this.profileImage = profileImage;
    }

    public Users(String uid, String name, String phoneNumber, String profileImage) {
        this.uid = uid;
        this.name = name;
        this.phoneNumber = phoneNumber;
        this.profileImage = profileImage;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Users() {}

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getProfileImage() {
        return profileImage;
    }

    public void setProfileImage(String profileImage) {
        this.profileImage = profileImage;
    }
}

I want to retrieve the data from the database and store it in this class so that I can use it later and I won't need to call the database again and again since I only need a single node's data.

The code I wrote-

FirebaseDatabase.getInstance().getReference().child("users").child(FirebaseAuth.getInstance().getUid())
                        .addValueEventListener(new ValueEventListener() {
                            @Override
                            public void onDataChange(@NonNull DataSnapshot snapshot) {
                                u = snapshot.getValue(Users.class);
                                Toast.makeText(ProfileActivity.this, u.getName(), Toast.LENGTH_SHORT).show();
                            }

                            @Override
                            public void onCancelled(@NonNull DatabaseError error) {

                            }
                        });
        binding.name.setText(u.getName());

Here, the first toast works, which means it shows the data I wanted. But whenever I use it somewhere else like the textview(name) it doesn't work and gives me this error-

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.joy.chat_two_point_o.models.Users.getName()' on a null object

I get it that somehow the User class getter gives a null value, but how did it work at first then? And why it doesn't work outside the onDataChange function? Can someone please explain? I tried to watch some videos but they use get() method instead of this "User Class" way. I read the documentation and did the same still it isn't working. Please tell me what am I doing wrong here?

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193

1 Answers1

1

I get it that somehow the User class getter gives a null value, but how did it work at first then?

When you read data from the Realtime Database, you actually perform an asynchronous operation. What you need to understand is that such an operation takes time. However, there is no way you can know ahead of time how much time it will take, as it depends on too many factors. So when you attach a listener to a reference, the onDataChange() method will fire when the operation for reading the data completes. This means that by the time you're using:

binding.name.setText(u.getName());

The operation for reading the data isn't complete, that's why u.getName() is null. The solution is always the same. Any code that needs data from the Realtime Database, needs to be inside the onComplete onDataChange() method or be called from there. So in your case that would be:

FirebaseDatabase.getInstance().getReference().child("users").child(FirebaseAuth.getInstance().getUid())
        .addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                u = snapshot.getValue(Users.class);
                Toast.makeText(ProfileActivity.this, u.getName(), Toast.LENGTH_SHORT).show();
                binding.name.setText(u.getName()); //
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                Log.d(TAG, "${it.exception?.message}") //Never ignore potential errors!
            }
        });

If you want to use the value u.getName() outside the onDataChange() method, then I recommend you use a callback. For more info, I recommend you can check the following article:

And the following video:

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193