You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

应用登录异常循环:点击登出后立即自动重新登录

登出后自动重新登录问题排查与修复

问题根源

  1. 永久监听导致的回调循环:你在logUserIn()和checkUserLogin()中使用了addValueEventListener,这是Firebase的永久监听API——只要目标节点的数据发生任何变化,就会重复触发onDataChange回调。
  2. 登出操作触发登录逻辑:点击登出调用setStatusLoggedOut()时,会将数据库中的SIGNEDIN设为false,此时logUserIn()的永久监听会捕捉到节点数据变动(哪怕只是SIGNEDIN字段修改),如果之前的memail和encryptedMsg仍保留正确值,就会重新执行登录验证,调用setStatusLoggedIn()导致自动登录。
  3. 冗余状态更新: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 19:40:34