How do I pass data out of the onDataChange method?

Viewed 1802

I have a boolean set up to check for duplicate usernames in an app. I want the boolean to return data based on the result of an onDataChange in a ValueEventListener. Here's what I have:

private boolean isUsernameValid(final String username) {


    mReference = FirebaseDatabase.getInstance().getReference();
    Query query = mReference.child("users").child(username);
    ValueEventListener mListener = new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            if (dataSnapshot.exists()) {

                //create condition that would make isUsernameValid return false

            }
        }

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

        }
    };

    mReference.addListenerForSingleValueEvent(mListener);

    return //if that condition is not met;
}
1 Answers

If you try to do something like this, you will always be returning false, since Firebase is asynchronous, you will need to wait a little bit depending on your connection in order to return any value from dataSnapshot()

private boolean isUsernameValid(final String username) {

        boolean isUsernameValid;
        mReference = FirebaseDatabase.getInstance().getReference();
        Query query = mReference.child("users").child(username);
        ValueEventListener mListener = new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                if (dataSnapshot.exists()) {

                    //create condition that would make isUsernameValid return false
                     isUsernameValid = true;
                }
            }

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

            }
        };

        mReference.addListenerForSingleValueEvent(mListener);

        return isUsernameValid //if that condition is not met;
    }

To solve this issue you can create an interface that will fires right when we know we have the results from onDataChange() and then you can return anything from there

first create an interface

public interface FirebaseSuccessListener {

    void onDataFound(boolean isDataFetched);

}

Then we just do your method that checks for the user if exists

private void isUsernameValid(final String username, FirebaseSuccessListener dataFetched) {


            mReference = FirebaseDatabase.getInstance().getReference();
            Query query = mReference.child("users").child(username);
            ValueEventListener mListener = new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    if (dataSnapshot.exists()) {

                        //here we are telling to our interface that the data has been found and then we can do anything with it outside this method
                         dataFetched.onDataFound(true);
                    }
                }

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

                }
            };

            mReference.addListenerForSingleValueEvent(mListener);


        }

And then we can call the method in order to get your value from inside onDataChange()

isUsernameValid.(new FirebaseSuccessListener() {
    @Override
    public void onCallback(boolean isDataFetched) {
        if(isDataFetched){
           //you know the value is true, here you can update or request any change for example you can do this 
            userIsOnFirebase(true);

      }else{
      userIsOnFirebase(false);
      }
    }
});


private boolean userIsOnFirebase(boolean isOnFirebase){
return isOnFirebase;
}

then use this method above to return if the user is or not in your db. Make sure when you call userIsOnFirebase since it will return false if the data is still not fetched

Related