r0d r0d - 12 days ago 7
Android Question

Firebase authentication, MainActivity calls itself onBackPressed

I'm currently trying to understand authentication with Firebase in Android. Currently the authentication itself is working like charm. I have a

LoginActivity
and a
MainActivity
which gets called if a user successfully authenticates.

This is my
LoginActivity
:

private static final String TAG = "LoginActivity";
EditText mEmailEdit;
EditText mPasswordEdit;
Button msignInButton;
TextView _signupLink;
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);

mAuth = FirebaseAuth.getInstance();

mAuthListener = new FirebaseAuth.AuthStateListener() {
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if (user != null) {
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.putExtra("userID", user.getUid());
startActivity(intent);
finish();
Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid());
} else {
Log.d(TAG, "onAuthStateChanged:signed_out");
}
}
};

mEmailEdit = (EditText) findViewById(R.id.input_email);
mPasswordEdit = (EditText) findViewById(R.id.input_password);

msignInButton = (Button) findViewById(R.id.btn_login);
msignInButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (validate(mEmailEdit.getText().toString(), mPasswordEdit.getText().toString())) {
mAuth.signInWithEmailAndPassword(mEmailEdit.getText().toString(), mPasswordEdit.getText().toString()).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
if (mAuth.getCurrentUser() != null) {
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.putExtra("userid", mAuth.getCurrentUser().getUid());
startActivity(intent);
finish();
}
}
});
}
}
});
}
@Override
public void onBackPressed() {
// disable going back to the MainActivity
moveTaskToBack(true);
}

public boolean validate(String email, String password) {
boolean valid = true;

if (email.isEmpty() || !android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
mEmailEdit.setError("Email is not valid");
valid = false;
} else {
mEmailEdit.setError(null);
}

if (password.isEmpty() || password.length() < 4 || password.length() > 10) {
mPasswordEdit.setError("between 4 and 10 alphanumeric characters");
valid = false;
} else {
mPasswordEdit.setError(null);
}

return valid;
}

@Override
public void onStart() {
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}

@Override
public void onStop() {
super.onStop();
if (mAuthListener != null) {
mAuth.removeAuthStateListener(mAuthListener);
}
}


And this is my
MainActivity
:

private FirebaseAuth mAuth;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

mAuth = FirebaseAuth.getInstance();

Button button = (Button) findViewById(R.id.logout);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mAuth.signOut();
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
});
}


So my issue is that after a user successfully authenticates and the
MainActivity
gets called, if I press back to close the app or return to my homescreen. What happens is that the
MainActivity
calls itself again. So after pressing back once I see another
MainActivity
popping up. After I press back on the new one again, it finally closes and goes back to the homescreen or whatever app I was in before.

I kind of fixed this by adding
android:launchMode="singleInstance"
to the
manifest
in the
activity
tag of the
MainActivity
, but I still do not know why the
MainActivity
called itself again when
android:launchMode
was not set and I really do want to understand it.

On another note I would also really like to know what the AuthStateListener is for. I don't understand why I would need this in my application. As I
finish();
the
LoginActivity
as soon as the user signs in, the
AuthStateChanged
event never gets called. So am I using it wrong or is it actually kind of useless?

Thanks in advance!

Answer

Edit : I think it's actually because MainActivity is being started twice - once in your onCompletion() and once in your authStateChanged().

When you press back, LoginActivity is called. However, since you are still logged in to Firebase, the AuthStateListener will fire with user != null and so the main activity gets called again. Depending on if you want the user to log in each time, you should override onBackPressed() in MainActivity and call the firebase logout function.

The firebase login persists across starts/restarts of your app, and the authstatelistener handles this.

Comments