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

Firebase Auth登出后重登闪退问题求助(附代码)

解决Firebase Email/Google Auth登出后重登闪退问题

看起来你遇到的是Firebase Auth登出流程中Activity栈管理和AuthStateListener回调冲突导致的闪退问题,结合你的代码细节,我整理了以下分析和修复方案:

问题根源拆解

  1. 未移除AuthStateListener引发的无效回调:你注册的AuthStateListener是全局监听Auth状态变化的,当你调用signOut()后,Listener会立即触发user==null的逻辑,但此时你已经调用finishAffinity()销毁了所有关联Activity,导致启动登录页时使用了已失效的Activity上下文,进而引发闪退(因为Android Monitor可能没捕获到这种上下文失效的崩溃,或者崩溃发生在主线程之外)。
  2. Activity栈管理混乱:finishAffinity()会清空整个Activity栈,但Firebase Auth的状态变化是异步的,当Listener触发时,栈中已经没有可用的Activity来承载登录页,导致崩溃。
  3. 登录取消时的栈清空操作:onActivityResult中登录取消时调用finishAffinity(),进一步加剧了栈的混乱,导致后续重启应用时的状态异常。

具体修复步骤

1. 登出时优先移除AuthStateListener

在登出流程中,先移除监听器,避免后续状态变化触发无效的登录页启动逻辑:

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    int id = item.getItemId(); 
    if (id == R.id.getOut) { 
        // 先移除AuthStateListener,阻止后续状态回调
        mFirebaseAuth.removeAuthStateListener(mAuthStateListener);
        mFirebaseAuth.getInstance().signOut(); 
        DetachReadListener(); 
        finishAffinity(); 
        return true; 
    } 
    return super.onOptionsItemSelected(item); 
}

注意:这里的mAuthStateListener是你注册时保存的实例,不要用匿名内部类注册,否则无法移除

2. 给AuthStateListener的登录页启动加安全校验

在onAuthStateChanged中,启动登录页前先检查当前Activity是否处于活跃状态,避免在Activity已销毁时执行启动操作:

public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { 
    FirebaseUser user = mFirebaseAuth.getCurrentUser(); 
    if (user!=null) { 
        // 保留你原有的已登录逻辑
        uid = user.getUid(); 
        if (user.getPhotoUrl()!=null) { 
            avatarurl = user.getPhotoUrl().toString(); 
            RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(getApplicationContext().getResources(),getImageBitmap(avatarurl)); 
            drawable.setCircular(true); 
            imgavatar.setImageDrawable(drawable); 
        } else imgavatar.setImageResource(R.drawable.ic_account_black_48dp); 
        mUsername = user.getDisplayName(); 
        username.setText(mUsername); 
        AttachReadListener(); 
        DatabaseReference usruid = usersref.child(uid).child("flag"); 
        usruid.addListenerForSingleValueEvent(new ValueEventListener() { 
            @Override 
            public void onDataChange(DataSnapshot dataSnapshot) { 
                while (!dataSnapshot.exists()) { 
                    pb.setContentView(R.layout.activity_progress_bar); 
                    pb.requestWindowFeature(Window.FEATURE_NO_TITLE); 
                    pb.show(); 
                } 
                val = dataSnapshot.getValue(String.class); 
            } 
            @Override 
            public void onCancelled(DatabaseError databaseError) { } 
        }); 
    } else { 
        // 检查Activity是否未被销毁,再启动登录页
        if (!isFinishing() && !isDestroyed()) {
            startActivityForResult( 
                AuthUI.getInstance() 
                    .createSignInIntentBuilder() 
                    .setIsSmartLockEnabled(false) 
                    .setTheme(R.style.LoginTheme) 
                    .setLogo(R.drawable.firstlogo) 
                    .setAvailableProviders(Arrays.asList(
                        new AuthUI.IdpConfig.Builder(AuthUI.EMAIL_PROVIDER).build(),
                        new AuthUI.IdpConfig.Builder(AuthUI.GOOGLE_PROVIDER).build()
                    )) 
                    .build(), RC_SING_IN 
            ); 
        }
    } 
};

3. 优化登出时的Activity栈操作

替换finishAffinity()为更可控的栈清理方式,确保登录页能正常启动:

if (id == R.id.getOut) { 
    mFirebaseAuth.removeAuthStateListener(mAuthStateListener);
    mFirebaseAuth.getInstance().signOut(); 
    DetachReadListener(); 
    // 启动登录页并清空栈,避免残留页面
    Intent loginIntent = new Intent(this, YourLoginActivity.class);
    loginIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    startActivity(loginIntent);
    finish();
    return true; 
}

如果你的登录逻辑就在当前Activity,可跳过启动登录页的步骤,直接重置UI状态

4. 调整登录取消时的退出逻辑

把onActivityResult中的finishAffinity()改为finish(),避免清空整个栈:

protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 
    if (requestCode == RC_SING_IN) { 
        if (resultCode == RESULT_CANCELED) { 
            // 仅关闭当前Activity,而非清空整个栈
            finish();
        } 
    } 
}

额外排查建议

  • 添加崩溃日志捕获:虽然Android Monitor没显示错误,但可以手动添加UncaughtExceptionHandler或者集成Firebase Crashlytics,捕获闪退时的异常堆栈,精准定位问题。
  • 避免匿名监听器:所有Firebase监听器(包括Auth和Database)都建议保存实例,在Activity生命周期的onDestroy()中移除,防止内存泄漏和无效回调。

内容的提问来源于stack exchange,提问作者scorpiogemini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:49:23