应用登录异常循环:点击登出后立即自动重新登录
登出后自动重新登录问题排查与修复
问题根源
- 永久监听导致的回调循环:你在
logUserIn()和checkUserLogin()中使用了addValueEventListener,这是Firebase的永久监听API——只要目标节点的数据发生任何变化,就会重复触发onDataChange回调。 - 登出操作触发登录逻辑:点击登出调用
setStatusLoggedOut()时,会将数据库中的SIGNEDIN设为false,此时logUserIn()的永久监听会捕捉到节点数据变动(哪怕只是SIGNEDIN字段修改),如果之前的memail和encryptedMsg仍保留正确值,就会重新执行登录验证,调用setStatusLoggedIn()导致自动登录。 - 冗余状态更新:
setStatusLoggedIn()每次都会强制设置SIGNEDIN为true,这又会触发checkUserLogin()的监听,造成不必要的循环回调。
修复方案
1. 单次读取替换永久监听
对于只需要读取一次数据库的操作(比如登录验证、启动时的状态检查),改用addListenerForSingleValueEvent,避免永久监听带来的意外回调:
private void logUserIn() { // 改用单次读取API,仅执行一次回调 reference.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { if (snapshot.exists()) { userdata = snapshot.child("email").getValue(String.class); userpassword = snapshot.child("password").getValue(String.class); if (userpassword.matches(encryptedMsg) && userdata.matches(memail)) { setStatusLoggedIn(snapshot); } else { Toast.makeText(getBaseContext(), "Wrong email or password please try again", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(getBaseContext(), "No account registered", Toast.LENGTH_SHORT).show(); } } @Override public void onCancelled(@NonNull DatabaseError error) { Toast.makeText(getBaseContext(), "Database error: " + error.getMessage(), Toast.LENGTH_SHORT).show(); } }); }
2. 优化登录状态更新逻辑
在setStatusLoggedIn()中先判断当前登录状态,仅当未登录时再更新SIGNEDIN字段,避免触发监听循环:
private void setStatusLoggedIn(DataSnapshot snapshot){ Boolean currentSignedIn = snapshot.child("SIGNEDIN").getValue(Boolean.class); // 仅当当前未登录时才更新状态,避免重复触发监听 if (currentSignedIn == null || !currentSignedIn) { reference.child("SIGNEDIN").setValue(true); } userdata = snapshot.child("email").getValue(String.class); et_email.setText(userdata); userpassword = snapshot.child("password").getValue(String.class); DecryptPassword(); btn_login.setText("Already Signed in"); btn_login.setOnClickListener(null); forgot_password.setVisibility(View.GONE); signup.setVisibility(View.GONE); tv_login_desc.setText("You Are Logged In "); btn_signout.setVisibility(View.VISIBLE); }
3. 管理实时监听的生命周期
如果需要保留实时监听登录状态的功能,必须在Activity生命周期结束时移除监听,防止内存泄漏和无效回调:
// 全局变量存储监听引用 private ValueEventListener loginStatusListener; private void checkUserLogin() { loginStatusListener = new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { signedin = snapshot.child("SIGNEDIN").getValue(Boolean.class); // 处理空指针,默认设为未登录 if (signedin != null && signedin) { setStatusLoggedIn(snapshot); }else { setStatusLoggedOut(); } } @Override public void onCancelled(@NonNull DatabaseError error) { Toast.makeText(getBaseContext(), "Database error: " + error.getMessage(), Toast.LENGTH_SHORT).show(); } }; reference.addValueEventListener(loginStatusListener); } // 在Activity销毁时移除监听 @Override protected void onDestroy() { super.onDestroy(); if (loginStatusListener != null) { reference.removeEventListener(loginStatusListener); } }
内容的提问来源于stack exchange,提问作者Mark Harrop
相关产品推荐
相关产品推荐

