1

I'm very new to Android dev and Firebase.

I need help with the below:

After a user authenticates with Firebase Password Authentication (fragment is called SignUp), this is saved as users->UID->person's email in the Realtime Database.Then, they move to a new fragment - AddUsername fragment. This fragment asks for a unique username.

What I am trying to achieve is if a user exits and closes the app without entering a username, the saved data from the Realtime Database is deleted from the Firebase Console and the user is taken back to the Sign Up fragment to restart the registration process. This prevents the creation of inactive email accounts or accounts that was mistakenly "exited" and the email address cannot be reused.

This is my code so far and I do not know what code I need to accomplish this.

EDIT: I've added this code on the onDestroyView() of AddUsername fragment. The data in the Realtime Database gets deleted when I press back the Back button but when I close the app, the data does not get deleted.

 @Override
public void onDestroyView() {
    super.onDestroyView();


    mAuth.signOut();

    mDatabase.child("users").child(user.getUid()).removeValue();
    Log.i("User: ", "Not saved in database");

    user.delete()
            .addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "User account deleted.");

                    }


                }



            });

}

Thank you in advance.


public class AddUsername extends Fragment implements View.OnClickListener, TextWatcher {

public AddUsername() {

}


public interface FragmentComm {
    void toSetName();
}

private TextView title, headings, handleError;
private EditText addUsername;
private Button nextButton;
private String getUsername;
private FirebaseAuth mAuth;
private FirebaseUser user;
private DatabaseReference mDatabase;
private FragmentComm fragmentComm;

@Override
public void onAttach(Context context) {
    super.onAttach(context);

    fragmentComm = (FragmentComm) getActivity();
    user = FirebaseAuth.getInstance().getCurrentUser();
    mAuth = FirebaseAuth.getInstance();
    mDatabase = FirebaseDatabase.getInstance().getReference();

}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.add_username, container, false);

    title = view.findViewById(R.id.username_title);
    headings = view.findViewById(R.id.display_user_message);
    handleError = view.findViewById(R.id.message_error);
    addUsername = view.findViewById(R.id.addUsername);
    nextButton = view.findViewById(R.id.nextButton);
    nextButton.setOnClickListener(this);
    addUsername.addTextChangedListener(this);


    return view;
}


@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

}


@Override
public void afterTextChanged(Editable s) {


    getUsername = addUsername.getText().toString();

    if (getUsername.isEmpty()) {

        handleError.setVisibility(View.GONE);
        nextButton.setBackgroundColor(Color.parseColor("#EEEEEE"));
        nextButton.setTextColor(Color.parseColor("#BDBDBD"));
        nextButton.setEnabled(false);


    } else {

        Query query = FirebaseDatabase.getInstance().getReference().child("users").orderByChild("username").equalTo(getUsername);
        query.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                if (dataSnapshot.exists()) {

                    handleError.setText(R.string.username_not_available);
                    handleError.setVisibility(View.VISIBLE);
                    handleError.setTextColor(Color.parseColor("#F50057"));
                    nextButton.setBackgroundColor(Color.parseColor("#EEEEEE"));
                    nextButton.setTextColor(Color.parseColor("#BDBDBD"));
                    nextButton.setEnabled(false);

                } else {

                    handleError.setText(R.string.username_available);
                    handleError.setVisibility(View.VISIBLE);
                    handleError.setTextColor(Color.parseColor("#26C485"));
                    nextButton.setBackgroundColor(Color.parseColor("#0277BD"));
                    nextButton.setTextColor(Color.parseColor("#FFFFFF"));
                    nextButton.setEnabled(true);

                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.i("Give info", "Error");


            }
        });

    }

}


@Override
public void onClick(View v) {

    switch (v.getId()) {

        case R.id.nextButton:

            checkUsernameAlreadyExist();

    }


}

private void checkUsernameAlreadyExist() {

    getUsername = addUsername.getText().toString();


    Query query = FirebaseDatabase.getInstance().getReference().child("users").orderByChild("username").equalTo(getUsername);
    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            if (dataSnapshot.exists()) {

                handleError.setText(R.string.username_not_available);
                handleError.setVisibility(View.VISIBLE);
                handleError.setTextColor(Color.parseColor("#F50057"));


            } else {

                handleError.setText(R.string.username_available);
                handleError.setVisibility(View.VISIBLE);
                handleError.setTextColor(Color.parseColor("#26C485"));

               fragmentComm.toSetName();
                setDatabaseName();

            }
        }


        @Override
        public void onCancelled(DatabaseError databaseError) {
            Log.i("Give info", "Error");


        }
    });

}


private void setDatabaseName() {

    mDatabase.child("users").child(user.getUid()).child("username").setValue(getUsername);


}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807

2 Answers2

4

I think this might be a good use-case for an onDisconnect handlers. These are write instructions that an app sends to the Firebase Database when it's connected, that the database server then executes once it detects that the client is gone.

An example of this:

private void setDatabaseName() {
  DatabaseReference usernameRef = mDatabase.child("users").child(user.getUid()).child("username");
  usernameRef.setValue(getUsername);
  usernameRef.onDisconnection().removeValue();
}

For more on this, see the Firebase documentation on onDisconnect handlers.

This will only work for the database though. You might have to find another way to also clean up the Firebase Authentication account.

Also note that the approach you're taking to ensure unique usernames is not very efficient. For a more idiomatic approach, see:

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thank you Frank. The onDisconnect worked by calling it in the onStop lifecycle of the fragment. Yes, I'm now looking a fix for the auth part. Thank you for the feedback regarding the unique usernames, very helpful resources. – Kasian Blithe Caballero May 27 '18 at 10:03
-1

I believe you need to add the same code used to delete it, wrapped with an if condition checking if user entered a username or not, in the onStop() and onDestroy() of the activity itself

However keep in mind, that if the application is onPause() it could be closed bypassing the onDestroy() and onStop() methods, so maybe you need to add your code in onPause() as well, but then on resume the user will need to start over from the beginning

Pierre Ghaly
  • 777
  • 2
  • 7
  • 17
  • Thank you for your suggestions PeeGee. Yes, that was my initial quick-fix solution as well. An if condition in the activity itself that checks whether a username is entered or empty when a user exits/minimise or X/closes the app. If it is empty, delete the data. When I look back, this doesn't provide a good user experience. A user might minimise the app (onPause called) without entering a username but the user shouldn't need to start over from the beginning. Only start over when the app is actually closed. – Kasian Blithe Caballero May 27 '18 at 09:59
  • Sure thing @KasianBlitheCaballero! Yes you are totally right but that was how far I could reach but the other answer provided is a way better solution, hats off! Good luck mate :) – Pierre Ghaly May 27 '18 at 13:46
  • This solution might not trigger efficiently. onDisconnect is triggered by Firebase because Firebase monitors the connection. – Emmanuel Conradie Feb 25 '21 at 08:05