1

I am trying to build a separate class for firebase methods, one of these methods is to return an Object User

    public User getUser(){
        myRef.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                User user = dataSnapshot.child("users").child(mUserID).child("user_info").getValue(User.class);
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.d(TAG, "onCancelled: Error: " + databaseError.getMessage());
            }
        });
        return user;
    }

returning the user gives me an error. is it possible to return the User user from the inner onDataChange() method? and how?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Ahmed Afifi
  • 391
  • 4
  • 16

3 Answers3

3

No, it's not possible because Firebase is asynchronous, and you're effectively trying to convert this method back into a blocking call by making the calling method "wait for" a returned object.

The appropriate pattern here is

1) make an interface.

public interface OnUserResult {
    void onUser(User u);
}

2) pass interface into void method
3) pass result back to Callback interface

public void getUser(final OnUserResult callback) {
    myRef.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            User user = dataSnapshot.child("users").child(mUserID).child("user_info").getValue(User.class);
           if (null!=callback) callback.onUser(user);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.d(TAG, "onCancelled: Error: " + databaseError.getMessage());
        }
    });
}

4) Rewrite the calling method to not expect a returned object

// Bad: User user = api.getUser();

// Good 
api.getUser(new OnUserResult() {
    @Override public void onUser(User u) {
         // Update the UI, or whatever 
        // Do not assign a global user variable here either 
    } 
});
// any external user variable will (usually) still be null here 

Libraries such as RxJava help you to implement this pattern in other ways

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • it works!.. thank you very much. but honestly i don't understand most it. can you please recommend for me a tutorial or something to help me understand it? – Ahmed Afifi Apr 08 '18 at 18:36
  • This is not specific to Android. It's just a generalized programming pattern for event driven systems... https://stackoverflow.com/q/443708/2308683 – OneCricketeer Apr 08 '18 at 18:39
1

It is not possible to return anything from an inner class.. But one can initialize an instance variable inside the inner class , making it accessible to all members of the class

zXor
  • 208
  • 1
  • 10
0

Is user declared in the scope of the class? Because otherwise I don't know how getUser() is accessing the user it is returning. Try declaring user in getUser() instead of inside onDataChange because the user in onDataChange is only in the scope of that method.

Also, if onDataChange is never called, there is never a declared User and it would return null

Peter Haddad
  • 78,874
  • 25
  • 140
  • 134