2

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;
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
andrewedgar
  • 797
  • 1
  • 12
  • 46
  • Please see my answer here where you can use the value from datasnapshot outside onDataChange https://stackoverflow.com/a/55741593/3904109 – DragonFire Apr 18 '19 at 08:16

1 Answers1

3

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

Gastón Saillén
  • 12,319
  • 5
  • 67
  • 77
  • Looks like I have some learning to do about threads. Thank you. – andrewedgar Sep 15 '18 at 21:05
  • 1
    I would highly recommend to you to follow this course from udacity https://www.udacity.com/course/android-basics-networking--ud843 – Gastón Saillén Sep 15 '18 at 21:18
  • Thank you. I certainly shall. If I could trouble you for one last syntax question: Where and how is that method being called in your third code block? What I have looks like this: `if (TextUtils.isEmpty(username)) { mUsernameView.setError(getString(R.string.error_field_required)); focusView = mUsernameView; } else if (!isUsernameValid(username, new FirebaseSuccessListener() { @Override public void onDataFound(boolean isDataFetched) { if (isDataFetched) { } }` – andrewedgar Sep 16 '18 at 00:32
  • isDataFetched is a variable of type boolean, is not a method, if you put if(isDataFetched) it means that if isDataFetched = true something happens else is false – Gastón Saillén Sep 16 '18 at 00:39
  • Right, I wasn't accurate. I'm confused about the beginning of the code block. Where might I put that relative to my other code? Not sure how to parse that first statement. – andrewedgar Sep 16 '18 at 00:55
  • about the interface? – Gastón Saillén Sep 16 '18 at 01:38
  • No. I'm wondering where this line begins: isUsernameValid.(new FirebaseSuccessListener() { – andrewedgar Sep 16 '18 at 06:24
  • I completed the tutorial, and although it was a nice review of the concepts, it did not really apply to this situation as Firebase's tools are already asynchronous. Can you be sure there are no implementations problems with your code? At the very least, our listener is wrong because we never attached the query properly. – andrewedgar Sep 27 '18 at 01:45