0

I am trying to access a users username to display on screen, and I am retrieving the username from my Firebase Database.

The code to get the username is kind of lengthy,

myRef.addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            String userName = dataSnapshot.child("userName").getValue(String.class);
            navUsername.setText(userName);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            throw databaseError.toException();
        }
    });

So I am trying to make it where that bit of code returns a string called 'specUserName' so that I can easily access it from any class without having to put in that lengthy string of code each time. In my User.class, I added this

    public String getUserName() {
    myRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            specUserName = dataSnapshot.child("userName").getValue(String.class);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            throw databaseError.toException();
        }
    });
    return specUserName;
}

And I am trying to retrieve that on in my HomePage.class by doing this

    users.getUserName();
    navUsername.setText(users.specUserName);

But now the HomePage keeps crashing whenever I open it up, and this is the error I am receiving in my Logcat.

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.example.brent.fifty_fifty.User.getUserName()' on a null object reference
    at com.example.brent.fifty_fifty.HomePage.onCreateOptionsMenu(HomePage.java:84)

HomePage:84 is where I am calling getUserName() method but it keeps returning null and crashing.

Any help?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
brent
  • 131
  • 12

2 Answers2

0

Data is loaded from Firebase asynchronously. Since you can't make getUserName wait until the data is available (that would mean your app become non-responsive), there is no way you can return the user name like that.

To understand why, place a few logging statements like this:

System.out.println("Before attaching listener");
myRef.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        System.out.println("Got data");
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        throw databaseError.toException();
    }
});
System.out.println("After attaching listener");

When you run this code it prints:

Before attaching listener

After attaching listener

Got data

That is probably not what you expected. But it definitely explains why you can't return a user name. By the time the return statement executes, the data hasn't loaded yet, and onDataChange() hasn't been called yet.

There are two common workaround for this:

  1. Move the code that needs the username into the getUserName method. This is by far the simplest, but makes your getUserName method less reusable.
  2. Create a callback interface, that you pass into getUserName and that you then call when the user name has been loaded. This is similar to what the ValueEventListener.onDataChange is for Firebase itself, but then specific to your app logic.

Instead of showing the code for both here, I recommend you check it out in my answer here: getContactsFromFirebase() method return an empty list

And to show that you're not alone in struggling with this, here are some previous questions about the topic:

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Hi Frank, this has really gotten me pretty close to solving my issue, so thanks a lot. I have looked through some of the other examples of this problem that you sent, and have been able to work some things out. I have my callback in place and everything set, but I am struggling on figuring out what exactly to call to retrieve the String that 'public void getUser(final MyCallback callback)' produces. I am calling the method properly where I need it as 'getUser(new MyCallback...), but I am trying to update the UI to display the persons username that is being retrieved, what variable do I put in – brent Oct 18 '18 at 13:23
  • place to set one of my TextViews to the string that 'public void getUser' produces? Sorry if this is a bit confusing in the comments - I can try to give some more info if you don't understand what I am asking – brent Oct 18 '18 at 13:24
  • Hey @CoderKlipto. Good to hear you made progress. I'm not sure I understand the new problem, but that's probably due to a lack of context. Instead of describing what you have, it's best to instead *show* the [minimal code that reproduces the problem](http://stackoverflow.com/help/mcve). At this point that might be better to post into a new question, as code in comments is quite hard to read beyond a single statement. – Frank van Puffelen Oct 18 '18 at 13:35
-1

This may happen due to various reasons and one of them might be that myRef is not given the correct reference to your database in your User class or any other reason.

However the issue you have to get the username, can be solved in various ways.

First, if you're using email/password to sign up the user, you already have the username of the user that they have in their GoogleID.

You can get that username easily just by this code:

FirebaseAuth mAuth = FirebaseAuth.getInstance();
String username = mAuth.getCurrentUser.getUsername();

Also it is easy to pass your data to the next activity if you have the data in one activity. You can do so with putExtra() method.

// to send data to MainActivity from the class where you first got username value

Intent intent = new Intent(getBaseContext(), MainActivity.class);
intent.putExtra("username", userName);
startActivity(intent);

// to recieve data in MainActivity

String uname = getIntent().getStringExtra("username");
PradyumanDixit
  • 2,372
  • 2
  • 12
  • 20