Why is my function returning before document/data retrieval from firestore is complete? Code Answer

Hello Developer, Hope you guys are doing great. Today at Tutorial Guruji Official website, we are sharing the answer of Why is my function returning before document/data retrieval from firestore is complete? without wasting too much if your time.

The question is published on by Tutorial Guruji team.

I am trying to make a function that checks if a username is taken or if it is available, how I have it in firestore is that the UniqueID is the username and not a field. This is the function:

private boolean checkUsernameValidity(String enteredUsername) {
    /**
     * Create code for querying through firestore DB for enteredUsername
     */
    final boolean[] usernameAvailable = {true};
    String USERTAG = "User documents";
    Log.d("Entered Username: ", enteredUsername);

    DocumentReference userDocRef = users.document(enteredUsername);

    userDocRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
            if (task.isSuccessful()) {
                DocumentSnapshot document = task.getResult();
                if (document.exists()) {
                    Log.d(USERTAG, "DocumentSnapshot data: " + document.getData());
                    Log.d("Warning", "Uh oh username is taken");
                    usernameAvailable[0] = false;
                    Toast.makeText(CreateAccount.this,
                            "This username is taken! Please enter a different username",
                            Toast.LENGTH_SHORT)
                            .show();
                } else {
                    Log.d(USERTAG, "No such document, This Username is available");
                }
            } else {
                Log.d(USERTAG, "get failed with ", task.getException());
            }
        }
    });

    /**
     * If there was a user with entered username found already;
     */

    if(!usernameAvailable[0]) {
        return false;
    }

    if (enteredUsername.length() < 5) {
        Toast.makeText(CreateAccount.this, "This username is too short",
                Toast.LENGTH_SHORT)
                .show();
        return false;
    }

    Log.d("Status", "All Good!");
    return true;
}

The function returns true according to the debugger before the usernameAvailable[0] is changed. Picture here:

Logs of the function

In the picture, the Log of a successful status is printed before the log that says that the username was taken. I’m guessing that the function needs to be an asynchronous or something along those lines but I’m not 100% on creating asynchronous methods. How do I make it so that my function retrieves the document if it exists and sets my usernameAvailable[0] to false inside the get document function before going through the rest of the checkUsernameValidity method.

P.S. usernameAvailable is a final array of booleans instead of just a boolean because it is accessed inside inner class

Answer

What you said is on the right track. The get() call you’re making on the DocumentReference internally starts an asynchronous task which defers the network request to a background thread. If this wasn’t the case then you would have a non-responsive app for the time it takes to receive the result. So instead of receiving the result synchoronously, in your code you attach an OnCompleteListener<*> which Firebase uses to call your onChanged method once the request is complete so that you can handle the result.

For a simple solution you can implement some sort of callback into checkUsernameValidity to process the result from wherever you are calling from. An implementation would look something like this:

interface Callback {

    void onResult(boolean valid);
}
void checkUsernameValidity(Callback callback) {

    userDocRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<DocumentSnapshot> task) {

            callback.onResult(true);
        }
    });
}

I would recommend doing some research on asynchronicity and the basic concept of callbacks.

We are here to answer your question about Why is my function returning before document/data retrieval from firestore is complete? - If you find the proper solution, please don't forgot to share this with your team members.

Related Posts

Tutorial Guruji