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

使用Firebase与Compose导航新页面时应用冻结求助

问题分析

应用冻结和Davey警告的核心原因是页面导航逻辑被重复触发,导致主线程被多次导航操作阻塞:

  • 当createUserResponse变为Success(true)后,Composable每次重组都会执行onNavigateToNewCondoScreen(),引发重复导航
  • 重复的导航操作会持续占用主线程资源,导致UI冻结并触发主线程超时的Davey警告
解决方案

1. 用LaunchedEffect控制导航仅执行一次

修改HandleCreateUserResponse,通过LaunchedEffect监听状态变化,确保导航只在Success(true)首次出现时执行:

@Composable
fun HandleCreateUserResponse(createUserResponse: Response<Boolean>, onNavigateToNewCondoScreen: () -> Unit) {
    when(createUserResponse) {
        is Loading -> ProgressBarVesta()
        is Success -> {
            LaunchedEffect(createUserResponse) {
                if (createUserResponse.data) {
                    onNavigateToNewCondoScreen()
                }
            }
        }
        is Failure -> Utils.print(createUserResponse.e)
    }
}

2. 重置ViewModel状态避免重复触发

在ViewModel中添加状态重置方法,导航完成后将createUserResponse恢复初始状态,防止后续重组再次触发导航:

@HiltViewModel
class SignupViewModel @Inject constructor(
    private val useCases: UserUseCases
) : ViewModel() {
    // 原有状态定义...

    fun resetCreateUserResponse() {
        createUserResponse = Success(false)
    }

    // 原有createUser方法...
}

在导航回调中调用该方法(示例基于NavController导航):

fun onNavigateToNewCondoScreen(navController: NavController, viewModel: SignupViewModel) {
    navController.navigate(Screen.NewCondo.route)
    viewModel.resetCreateUserResponse()
}

3. 可选:改用一次性事件处理导航

如果状态重置的方式不够优雅,可以用MutableSharedFlow实现一次性事件模式,彻底避免状态重复触发:

@HiltViewModel
class SignupViewModel @Inject constructor(
    private val useCases: UserUseCases
) : ViewModel() {
    // 原有状态定义...
    private val _navigateToNewCondo = MutableSharedFlow<Unit>(replay = 0)
    val navigateToNewCondo = _navigateToNewCondo.asSharedFlow()

    fun createUser(name: String, email: String, password: String) = viewModelScope.launch {
        // 原有验证逻辑...
        
        createUserResponse = Loading
        val result = useCases.createUser(trimmedName, trimmedEmail, password)
        createUserResponse = result
        if (result is Success && result.data) {
            _navigateToNewCondo.emit(Unit)
        }
    }
}

在Composable中收集事件执行导航:

@Composable
fun SignupScreen(viewModel: SignupViewModel = hiltViewModel(), navController: NavController) {
    // 原有UI逻辑...
    
    LaunchedEffect(Unit) {
        viewModel.navigateToNewCondo.collect {
            navController.navigate(Screen.NewCondo.route)
        }
    }
    
    HandleCreateUserResponse(viewModel.createUserResponse) {}
}
额外检查
  • Firebase操作部分的await()是挂起函数,不会阻塞主线程,现有代码逻辑无问题
  • 确认ProgressBarVesta()是轻量实现,未占用过多主线程资源

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:12:53