0

I am trying to fetch the user details of a particular user using his UID. I need a method that can return the userName as a String type so that I can store it and display it in my app.

getUserName("UID");

This is how my database looks like - enter image description here

This is what i tried doing -

 private String getUserName(String startedBy) {
    mProfileRef=database.getReference("Profile").child(startedBy).child("UserDetails").child("userName");
    mProfileRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            userName = dataSnapshot.getValue(String.class);
            Log.i(TAG, "onDataChange: "+userName);

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
    return userName;
}

The Log statement executes perfectly and gives the correct userName based on the UID. The method does not return the userName. It returns null. How do I return the userName?

ReyAnthonyRenacia
  • 17,219
  • 5
  • 37
  • 56
knightcube
  • 139
  • 1
  • 13
  • @Dumbo it is the UID of the user whose userName is needed – knightcube Mar 29 '18 at 06:57
  • 1
    Possible duplicate of [How to return dataSnapshot value as a result of a method?](https://stackoverflow.com/questions/47847694/how-to-return-datasnapshot-value-as-a-result-of-a-method) – Alex Mamo Mar 29 '18 at 10:00
  • Please check the duplicate to see the exact reason why is happening this. – Alex Mamo Mar 29 '18 at 10:00

2 Answers2

3

It is because Firebase operations are performed asynchronous. That means the method onDataChange executes on a background thread meanwhile your UI thread executes the original method and returns the value without waiting for the Firebase response.

The solution can be done with using an interface.

1 - Define an interface

public interface OnDataLoaded {

   onDataLoaded(String username);

}

2 - Pass the interface as the method argument

public void getUserName(String startedBy, OnDataLoaded onDataLoaded)

3 - Use the interface to pass the username.

mProfileRef = database.getReference("Profile").child(startedBy).child("UserDetails").child("userName");
mProfileRef.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        userName = dataSnapshot.getValue(String.class);
        onDataLoaded.onDataLoaded(username);
        Log.i(TAG, "onDataChange: "+userName);

    }

    @Override
    public void onCancelled(DatabaseError databaseError) {

    }
});

4 - Use the interface in your Activity/Fragment.

public class yourActivity implements OnDataLoaded 

5 - You control will be transfered to you activity method onDataLoaded

@Override
public void onDataLoaded(String userName) {
    // your userName will be available here.
    // you can use your bindings here.
}

NOTE : wrote with without any IDE. Might contain some syntax errors.

Dumbo
  • 1,630
  • 18
  • 33
M.Waqas Pervez
  • 2,492
  • 2
  • 19
  • 33
0

You can directly update your view inside the call back for firebase database read given your firebase code is also in the same class.

private void getUserName(String startedBy, TextView textView) {
    mProfileRef=database.getReference("Profile").child(startedBy).child("UserDetails").child("userName");
    mProfileRef.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            userName = dataSnapshot.getValue(String.class);
            textView.setText(userName);
            Log.i(TAG, "onDataChange: "+userName);

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
}

The answer from Waqas Pervez is also a very good solution.

Dumbo
  • 1,630
  • 18
  • 33
Umar Hussain
  • 3,461
  • 1
  • 16
  • 38