0

Cannot get Firebase to identify a username that has already been entered. The code below shows that I am trying to compare the username entered with a DataSnapshot of my database. The code doesn't seem to pick up usernames that are entered. Is the code wrong?

private boolean mSwitch = false;

public void checkInfo(View view){

    checkUsernameIsUnique();
    checkInformation();

    if(mSwitch) {
        Intent intent = new Intent(getApplicationContext(), MenuActivity.class);
        saveUserInformation();
        startActivity(intent);
    }
}

public void checkUsernameIsUnique(){

    String username = Username.getText().toString().trim();

    DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
    DatabaseReference usernameRef = rootRef.child("user_profile_info").child(userID);
    Query checkName = usernameRef.equalTo(username);
    checkName.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            String name = Username.getText().toString().trim();
            for (DataSnapshot ds : dataSnapshot.getChildren()) {
                if(name.equals(ds.child("username").getValue(String.class))){

                    Username.setError("Username Taken");
                    Username.requestFocus();

                } else {
                    Toast.makeText(ProfileActivity.this, "Registered User", Toast.LENGTH_SHORT).show();
                    mSwitch = true;
                }
            }
        }

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

        }
    });

    if(Username.getText().toString().equals("")){

        Username.setError("A Username is Required");
        Username.requestFocus();

    }

    if(Username.length() < 5){

        Username.setError("Username must be 5 characters minimum");
        Username.requestFocus();

    }
}

On button click I wish to be able to direct the user to the error, and until it is unique the page should not be pushed to the next activity.


The JSON tree if it helps

"user_profile_info" : {
    "8FUV95JorVT26Gd1QFNUbxEf8O93" : {
      "date_of_birth" : "2/5/1925",
      "diet" : "Moderate",
      "drinker" : "No",
      "education" : "Masters Degree",
      "exercise" : "3 - 5 Hours a Week",
      "forename" : "Ben",
      "gender" : "Male",
      "have_alzheimers" : "No",
      "have_diabetes" : "No",
      "have_parkinsons" : "No",
      "history_alzheimers" : "No",
      "history_diabetes" : "No",
      "history_parkinsons" : "No",
      "marital_status" : "Single",
      "smoker" : "No",
      "surname" : "Dover",
      "username" : "Maturity101"
    }
Sean O
  • 238
  • 3
  • 14
  • @AlexMamo: while the question you linked is relevant, this is not a duplicate of that question. Sean's code is not handling the asynchronous nature of the database, which Teempy explains in their answer. – Frank van Puffelen Sep 08 '19 at 14:20
  • @FrankvanPuffelen Fair enough and thanks for reopening the question. – Alex Mamo Sep 09 '19 at 08:36

1 Answers1

2

addListenerForSingleValueEvent is an asynchronous operation. After the callback onDataChange() is set the code continues running while you have not fetched any usernames yet. By the time you check for mSwitch value its always false, even if the username is OK.

To make it working you should move your

checkInformation();
if(mSwitch) {
    Intent intent = new Intent(getApplicationContext(), MenuActivity.class);
    saveUserInformation();
    startActivity(intent);
}

to the end of the onDataChange() callback.

Also it would be better to first for check empty string and length before you query for documents. Just to cut useless data downloaded from the database.

But it seems that it still won't be working because of the for loop. Try smth like that:

mSwitch = true; // as its OK
for (DataSnapshot ds : dataSnapshot.getChildren()) {
  if(name.equals(ds.child("username").getValue(String.class))){
    mSwitch = false;
    Username.setError("Username Taken");
    Username.requestFocus();
    break;
  }
}

...
if (mSwitch) startActivity();
else showErrorToast();
Teempy
  • 491
  • 4
  • 11
  • Hi Teempy, thanks for your answer. In your answer have you moved the mSwitch to the outside of the for loop and into the onCancelled? @Teempy – Sean O Sep 08 '19 at 08:34
  • Sean, as Alex Mamo marked it as duplicate. You dont need for loop XD. You can just take the doc with the wanted username and check if it exists or not. That way mSwitch is also useless – Teempy Sep 08 '19 at 12:29
  • Yes, I seen the link he posted. Took me a while to understand it haha. Eventually I saw the [video](https://youtu.be/66lDSYtyils?t=379) which explains that you need the username to be a key and not a value. Alex Mamo's post was confusing because of the two similar key and value names. Thanks anyway @Teempy! – Sean O Sep 08 '19 at 12:37