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

Firebase Authentication导致界面卡顿问题排查与优化需求

问题描述

遇到Firebase Authentication导致界面卡顿的问题,不清楚原因。以下是MainActivity.kt、AuthState可组合项、AuthViewModel及EmailAuthRepositoryImpl的代码,希望解决卡顿问题,让登录界面更流畅,同时排查其他潜在问题并获取优化建议。

MainActivity.kt

class MainActivity : ComponentActivity() {
    private lateinit var navHostController: NavHostController

    private val deepLinkViewModel: DeepLinkViewModel by viewModel()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            KoinContext {
                CountryAppTheme {
                    Surface(
                        modifier = Modifier.fillMaxSize(),
                        color = MaterialTheme.colorScheme.background
                    ) {
                        navHostController = rememberNavController()
                        deepLinkViewModel.handleDeepLink(intent, navHostController)
                        NavGraph(
                            navHostController = navHostController,
                        )
                        AuthState(navHostController = navHostController)
                    }
                }
            }
        }
    }
}

AuthState 可组合项

@Composable
fun AuthState(
    navHostController: NavHostController,
    viewModel: AuthViewModel = koinViewModel(),
) {
    val isUserSignedOut = viewModel.getAuthState().collectAsState().value
    if (isUserSignedOut) {
        Log.i(TAG, "viewModel.isUserSignedOut: $isUserSignedOut ")
        NavigateToSignInScreen(navController = navHostController)
    } else {
        if (viewModel.isEmailVerified) {
            Log.i(TAG, "viewModel.isEmailVerified: ${viewModel.isEmailVerified}")
            NavigateToMapsScreen(navController = navHostController)
        } else {
            Log.i(TAG, "viewModel.isEmailNotVerified: ${viewModel.isEmailVerified}")
            NavigateToVerifyEmailScreen(navController = navHostController)
        }
    }
}

@Composable
private fun NavigateToSignInScreen(navController: NavController) =
    navController.navigate(Screen.SignInScreen.route) {
        popUpTo(navController.graph.id) {
            inclusive = true
        }
    }

@Composable
private fun NavigateToMapsScreen(navController: NavController) =
    navController.navigate(Screen.TabLayoutScreen(args = "/${Locale.getDefault().displayCountry}").route) {
        popUpTo(navController.graph.id) {
            inclusive = true
        }
    }

@Composable
private fun NavigateToVerifyEmailScreen(navController: NavController) = navController.navigate(
    Screen.VerifyEmailScreen.route
) {
    popUpTo(navController.graph.id) {
        inclusive = true
    }
}

AuthViewModel

class AuthViewModel(
    private val repo: EmailAuthRepository
): ViewModel() {


    init {
        getAuthState()
    }

    fun getAuthState() = repo.getAuthState(viewModelScope = viewModelScope)

    val isEmailVerified get() = repo.currentUser?.isEmailVerified ?: false
}

EmailAuthRepositoryImpl

class EmailAuthRepositoryImpl(
    private val auth: FirebaseAuth,
    private val db: FirebaseFirestore,

    ) : EmailAuthRepository {

    override val currentUser: FirebaseUser?
        get() = auth.currentUser

    override fun getAuthState(viewModelScope: CoroutineScope) = callbackFlow {
        val authStateListener = AuthStateListener { auth -
            trySend(auth.currentUser == null)
        }
        auth.addAuthStateListener(authStateListener)
        awaitClose {
            auth.removeAuthStateListener(authStateListener)
        }
    }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), auth.currentUser == null)
}
优化及修复建议
  • 修复导航重复触发导致的卡顿:当前AuthState直接在Composable代码块中调用导航方法,每次重组都会执行导航逻辑,引发频繁跳转和界面卡顿。需用LaunchedEffect包裹导航逻辑,仅在状态变化时触发一次:

    @Composable
    fun AuthState(
        navHostController: NavHostController,
        viewModel: AuthViewModel = koinViewModel(),
    ) {
        val isUserSignedOut = viewModel.getAuthState().collectAsState().value
        val isEmailVerified = viewModel.getEmailVerifiedState().collectAsState().value
    
        LaunchedEffect(isUserSignedOut, isEmailVerified) {
            when {
                isUserSignedOut -> {
                    Log.i(TAG, "viewModel.isUserSignedOut: $isUserSignedOut ")
                    navHostController.navigate(Screen.SignInScreen.route) {
                        popUpTo(navHostController.graph.startDestinationRoute!!) { inclusive = true }
                    }
                }
                isEmailVerified -> {
                    Log.i(TAG, "viewModel.isEmailVerified: $isEmailVerified")
                    navHostController.navigate(Screen.TabLayoutScreen(args = "/${Locale.getDefault().displayCountry}").route) {
                        popUpTo(navHostController.graph.startDestinationRoute!!) { inclusive = true }
                    }
                }
                else -> {
                    Log.i(TAG, "viewModel.isEmailNotVerified: $isEmailVerified")
                    navHostController.navigate(Screen.VerifyEmailScreen.route) {
                        popUpTo(navHostController.graph.startDestinationRoute!!) { inclusive = true }
                    }
                }
            }
        }
    }
    
  • 修复Repository语法错误:AuthStateListener的lambda表达式写法有误,auth -应改为auth ->,否则会引发编译错误或逻辑异常:

    val authStateListener = AuthStateListener { auth ->
        trySend(auth.currentUser == null)
    }
    
  • 实现验证状态的响应式更新:当前isEmailVerified直接读取currentUser属性,无法在用户完成邮箱验证后自动更新UI。需将其改为Flow,同步AuthState变化:

    // EmailAuthRepository中新增方法
    override fun getEmailVerifiedState(viewModelScope: CoroutineScope): Flow<Boolean> = callbackFlow {
        val authStateListener = AuthStateListener { auth ->
            trySend(auth.currentUser?.isEmailVerified ?: false)
        }
        auth.addAuthStateListener(authStateListener)
        awaitClose { auth.removeAuthStateListener(authStateListener) }
    }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000L), auth.currentUser?.isEmailVerified ?: false)
    
    // AuthViewModel中暴露Flow
    fun getEmailVerifiedState() = repo.getEmailVerifiedState(viewModelScope)
    
  • 移除ViewModel无用初始化代码:init { getAuthState() }无实际作用,因为getAuthState()返回的Flow需要UI层collect才会生效,直接调用不会触发逻辑,可删除。

  • 修复DeepLink重复处理问题:MainActivity中直接在Composable里调用deepLinkViewModel.handleDeepLink,每次重组都会执行,可能导致重复处理DeepLink。用LaunchedEffect包裹,仅初始化时执行一次:

    navHostController = rememberNavController()
    LaunchedEffect(Unit) {
        deepLinkViewModel.handleDeepLink(intent, navHostController)
    }
    
  • 优化Flow订阅策略:将Repository中stateIn的SharingStarted.WhileSubscribed()调整为SharingStarted.WhileSubscribed(5000L),用户离开界面后延迟5秒取消订阅,减少不必要的资源占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:46:23