Firebase Android onAuthStateChanged()在signInWithEmailAndPassword()后触发两次

当我使用signInWithEmailAndPassword()来loginonAuthStateChanged()总是会触发两次。

我非常肯定,这个监听只添加了一次到firebaseAuth, and I have the code in onStop()中firebaseAuth, and I have the code in来删除这个监听器。

有谁知道如何解决这个问题?

我的代码:

 public class SignInActivity extends BaseActivity implements View.OnClickListener, GoogleApiClient.OnConnectionFailedListener{ private static final String PREF_KEY_USER_EMAIL = "User_Email"; private static final int RC_SIGN_IN = 1111; private FirebaseAuth firebaseAuth; private FirebaseAuth.AuthStateListener authStateListener; private DatabaseReference firebaseDbReference; private TextView fieldEmail; private TextView fieldPassword; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sign_in); getSupportActionBar().hide(); firebaseAuth = FirebaseAuth.getInstance(); firebaseDbReference = FirebaseDatabase.getInstance().getReference(); fieldEmail = (TextView) findViewById(R.id.field_email); fieldPassword = (TextView) findViewById(R.id.field_password); String userSavedEmail = getPreferences(MODE_PRIVATE).getString(PREF_KEY_USER_EMAIL, ""); if(userSavedEmail != null) { fieldEmail.setText(userSavedEmail); fieldPassword.requestFocus(); } TextView linkForgotPassword; Button buttonLogin; linkForgotPassword = (TextView) findViewById(R.id.link_forgotPassword); buttonLogin = (Button) findViewById(R.id.button_Login); buttonSignUp = (Button) findViewById(R.id.button_signUp); if (linkForgotPassword != null) { linkForgotPassword.setOnClickListener(this); } if (buttonLogin != null) { buttonLogin.setOnClickListener(this); } if (buttonSignUp != null) { buttonSignUp.setOnClickListener(this); } authStateListener = new FirebaseAuth.AuthStateListener() { @Override public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { if(firebaseAuth.getCurrentUser() != null) { onAuthSuccess(firebaseAuth.getCurrentUser()); } } }; } @Override protected void onStart() { super.onStart(); firebaseAuth.addAuthStateListener(authStateListener); } @Override protected void onStop() { super.onStop(); if (authStateListener != null) { firebaseAuth.removeAuthStateListener(authStateListener); } } @Override public void onClick(View v) { switch (v.getId()){ case R.id.link_forgotPassword: forgotPassword(); break; case R.id.button_Login: emailLogin(); break; case R.id.button_signUp: emailSignUp(); break; } } @Override public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { Toast.makeText(this, "Google Play Services error.", Toast.LENGTH_SHORT).show(); } private void forgotPassword(){ FirebaseAuth auth = FirebaseAuth.getInstance(); String emailAddress = fieldEmail.getText().toString(); if(TextUtils.isEmpty(emailAddress)){ Toast.makeText(SignInActivity.this, R.string.msg_EnterEmail, Toast.LENGTH_SHORT).show(); } else { showProgressDialog(); auth.sendPasswordResetEmail(emailAddress) .addOnCompleteListener(new OnCompleteListener<Void>() { @Override public void onComplete(@NonNull Task<Void> task) { hideProgressDialog(); if (task.isSuccessful()) { Toast.makeText(SignInActivity.this, R.string.msg_ResetPasswordEmailSent, Toast.LENGTH_LONG).show(); } } }); } } private void emailLogin(){ if (!validateForm()) { return; } showProgressDialog(); String email = fieldEmail.getText().toString(); String password = fieldPassword.getText().toString(); firebaseAuth.signInWithEmailAndPassword(email, password) .addOnCompleteListener(new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { hideProgressDialog(); if (!task.isSuccessful()) { Toast.makeText(SignInActivity.this, R.string.msg_EmailLoginFailed, Toast.LENGTH_SHORT).show(); } else { // Save the email getPreferences(MODE_PRIVATE).edit() .putString(PREF_KEY_USER_EMAIL, fieldEmail.getText().toString()) .apply(); } } }); } private void emailSignUp(){ if (!validateForm()) { return; } showProgressDialog(); String email = fieldEmail.getText().toString(); String password = fieldPassword.getText().toString(); firebaseAuth.createUserWithEmailAndPassword(email, password) .addOnCompleteListener(new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { hideProgressDialog(); if (task.isSuccessful()) { FirebaseUser user = task.getResult().getUser(); String displayName = displayNameFromEmail(user.getEmail()); // Update profile display name. UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder() .setDisplayName("Jane Q. User") .build(); user.updateProfile(profileUpdates); } else { Toast.makeText(SignInActivity.this, R.string.msg_EmailSignUpFailed, Toast.LENGTH_SHORT).show(); } } }); } private void onAuthSuccess(FirebaseUser user) { // Write new user writeNewUser(user.getUid(), user.getDisplayName(), user.getEmail(), user.getPhotoUrl()); // Go to MainActivity startActivity(new Intent(this.getApplicationContext(), MainActivity.class)); finish(); } private void writeNewUser(String userId, String displayName, String email, android.net.Uri photoUrl) { User user = new User(displayName, email); if(photoUrl != null){ user.setPhotoUrl(photoUrl.toString()); } firebaseDbReference.child("users").child(userId).setValue(user); } private String displayNameFromEmail(String email) { if (email.contains("@")) { return email.split("@")[0]; } else { return email; } } private boolean validateForm() { boolean result = true; if (TextUtils.isEmpty(fieldEmail.getText().toString())) { fieldEmail.setError("Required"); result = false; } else { fieldEmail.setError(null); } if (TextUtils.isEmpty(fieldPassword.getText().toString())) { fieldPassword.setError("Required"); result = false; } else { fieldPassword.setError(null); } return result; } } 

Solutions Collecting From Web of "Firebase Android onAuthStateChanged()在signInWithEmailAndPassword()后触发两次"

它确实发生了两次,我认为这是一个Firebase家伙应该修复的错误(看你Frank Hehehe)。 我认为你现在唯一能做的就是添加一个这样的标志。

 private boolean flag = true; ... authStateListener = new FirebaseAuth.AuthStateListener() { @Override public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { if(firebaseAuth.getCurrentUser() != null && flag) { onAuthSuccess(firebaseAuth.getCurrentUser()); flag=false; } } }; 

远非理想,但现在会工作。 代码仍然会触发两次,我们接受第一个,并用我们的国旗拒绝第二个,这样,如果Firebase的人修复它,突然听众运行一次,我们的代码仍然工作。 也许这是为了让听众跑两遍,希望我们能从弗兰克的交叉post中得到一些答案

双重电话是由于注册电话。 不仅如此,onAuthStateChanged将在很多不同的状态被多次调用,而不可能知道它是哪个状态。

文档说:

onAuthStateChanged(FirebaseAuthvalidation)

这个方法在UI线程中被authentication状态的变化调用:

  • 听众注册后

  • 当用户login时

  • 当前用户注销时
  • 当前用户更改时
  • 当前用户令牌发生变化时

这里有一些提示来发现当前状态:

  • 注册电话:跳过带有标志的第一个电话。
  • 用户login:用户从参数是!=空。
  • 用户退出:用户从参数是== null。
  • 当前用户更改:来自参数的用户是!= null,最后一个用户标识是!=来自参数的用户标识
  • 用户令牌刷新:来自参数的用户是!= null,最后一个用户ID是来自参数的用户ID

这个听众是一个混乱,很bugprone。 Firebase团队应该研究它。

也不是太理想,而是更准确的解决scheme。

 private String authFlag = ""; ... authStateListener = new FirebaseAuth.AuthStateListener() { @Override public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { if (firebaseAuth.getCurrentUser() == null) { if (authFlag != null) { authFlag = null; subscriber.onNext(null); } } else { String uid = firebaseAuth.getCurrentUser().getUid(); if (authFlag == null || authFlag.isEmpty() || !authFlag.equals(uid)) { authFlag = uid; subscriber.onNext(firebaseAuth.getCurrentUser()); } } }