1

I am trying to check for an entry in my Firebase Database asynchronously using an interface, but I'm not sure how to implement it in the same way I have for password and email.

Example:

if (TextUtils.isEmpty(password) || !isPasswordValid(password)) {
            mPasswordView.setError(getString(R.string.error_invalid_password));
            focusView = mPasswordView;
            cancel = true;
        }

private boolean isPasswordValid(String password) {

        // Add logic to check for a valid password (minimum 8 characters)

        String confirmPassword = mConfirmPasswordView.getText().toString();
        return (confirmPassword.equals(password)) && (password.length() > 7) && (password != "12345678") && (password != "password");
    }

I am attempting to create a similar method with username that checks for the entered username in Firebase and then returns true if data is found. I've created a method (fetchUsername) to check for the name in Firebase on the background thread, but cannot figure out how to properly pass the result back to the final method and return a boolean. I believe I'm making a silly syntax error, but I can't see it. Here is what I have:

private boolean isUsernameDuplicate(final String username) {

    boolean userIsOnFirebase ( boolean isOnFirebase){ ///<----line that won't take, wants semicolon after variable
        if (isOnFirebase) {
            return true;
        } else {
            return false;
        }
    }

    fetchUsername(username, new FirebaseSuccessListener() {
        @Override
        public void onDataFound(boolean isDataFetched) {
            if (isDataFetched) {

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

    return userIsOnFirebase;
}


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

    //checks database for username

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

                dataFetched.onDataFound(true);
            }

        }

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

        }
    });

}


public interface FirebaseSuccessListener {
    void onDataFound(boolean isDataFetched);
}

Edit: Here is my solution:

    //member Variables
    String checkedUsername;

private void attemptRegistration() {

    // Reset errors displayed in the form.
    mEmailView.setError(null);
    mPasswordView.setError(null);
    checkedUsername=null;

    // Store values at the time of the login attempt.
    String email = mEmailView.getText().toString();
    String password = mPasswordView.getText().toString();
    String username = mUsernameView.getText().toString();
    boolean cancel = false;
    View focusView = null;



        if (TextUtils.isEmpty(username)) {
            mUsernameView.setError(getString(R.string.error_field_required));
            focusView = mUsernameView;
            cancel = true;
        }
        if (!isUsernameValid(username)) {
            mUsernameView.setError("Username is taken");
            focusView = mUsernameView;
            cancel = true;
        }

private boolean isUsernameValid(String username) {
        if (!duplicateUsername(username)) {
            return true;
        } else {
            Toast.makeText(this, "Username is taken", Toast.LENGTH_LONG);
            return false;

        }
    }


    private boolean duplicateUsername(String username) {

        if (fetchUsername(username) != null) {
            return true;
        }

        return false;

    }

    private String fetchUsername(final String username) {

        //checks database for username

        mReference = FirebaseDatabase.getInstance().getReference().child("users");
        mReference.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                if (dataSnapshot.exists()) {
                    User user = new User();
                    user = dataSnapshot.getValue(User.class);
                    if (user.getUsername() == username) {
                        checkedUsername = user.getUsername();

                    }

                }

            }

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

            }
        });

        return checkedUsername;

    }
andrewedgar
  • 797
  • 1
  • 12
  • 46
  • 1
    Communication with Firebase using it's methods is already made to run asynchronously. Depending on your request: `onCompleteListener` or `onSuccessListener`, `onDataChange` etc are callbacks which are running on UI thread brining results from Firebase, so you can update your UI inside of an of those call-backs. You don't have to complicated things with creating your own `interfaces` – Yupi Sep 27 '18 at 23:18
  • Thank you for responding. How do I get data out of onDataChanged to tell a different part of the activity that the user has been found? Inititializing a variable outside if that method forces me to make it final once it is used in there. – andrewedgar Sep 28 '18 at 14:35
  • 1
    Nope if `variable` is created as `field`. You can update UI inside `onDataChange` whatever you need to update on UI for example present founded user with his name. – Yupi Sep 28 '18 at 18:27
  • Apologies for being so dense, but I think I am misunderstanding you. Here is a screenshot of my attempt at what you've described and the error I get when I try to create the variable as a field. https://imgur.com/a/4rb7WaG – andrewedgar Sep 28 '18 at 21:54
  • 1
    `Field` variable is a `variable` declared inside the class not inside method. `Variable` inside method is local variable. So you will have something like this: `public class YourClassName { private String fetchedUsername }` You can take a look here: https://stackoverflow.com/questions/10115588/what-is-the-difference-between-field-variable-attribute-and-property-in-java – Yupi Sep 28 '18 at 22:29
  • Also that method will not work properly I mean you will not get expected result, `return fetchedusername` will return `null` or initial value if it's set. – Yupi Sep 28 '18 at 22:36

1 Answers1

1

Here is an explanation. First of all field variable is a variable created inside the class and can be accessed by all members of that class. On another side variable created inside a method can only be access by the members of that method not of rest of the members of the class.

Firebase runs asynchronously (reading and writing to database) and implements its own callbacks which are called on UI thread. For example one of those callbacks (depending from scenario) which you can implement are: onSuccessListener, addOnFailureListener, onCompleteListener, onDataChange. This callbacks give you informations from Firebase (in this case database) either writing was successfully or reading was successfully and you have your data ready for usage in app or something went wrong. Inside these callbacks you can easily update your UI.

What are you doing now is you are creating an interface which is going to be triggered when this callbacks are triggered and that is one unnecessary step as you can easily update UI inside the callback directly.

Also method you are creating where you want to return name of user will not work as expected. Why? Because part of the code return fetchedusername is executed before result is returned from database. As you already know Fireabse runs asynchronously and needs to get data over the internet and meantime return fetchedusername is already executed. That is why you have callback methods.

Hope this clears some things.

Yupi
  • 4,402
  • 3
  • 18
  • 37
  • I believe I was able to finally piece enough of everything together. Thank you for your help and your patience. See my solution in the edit. – andrewedgar Sep 28 '18 at 23:06