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

Jetpack Compose中主页与认证导航流程问题求助

Compose 双导航图(认证/主功能)+ Splash Screen 导航问题修复

问题背景

在Compose应用中实现双导航图(认证流程+登录后主功能模块),并使用Android 12 Splash Screen API时遇到了核心问题:通过Activity中的普通变量userAuthState收集ViewModel的StateFlow判断认证状态,但登录后when语句不会重新执行——因为Activity仅创建一次,Compose无法感知普通变量的状态变化,导致页面无法自动切换到主功能模块。

核心解决思路

让Composable能够感知认证状态的变化,触发UI重组:

  • 在Composable内部直接收集ViewModel的StateFlow(使用collectAsState()),状态变更时自动触发重组
  • 登录/登出操作完成后,同步更新ViewModel中的认证状态
  • 调整Splash Screen的保持逻辑,基于Composable内的可观察状态

修改后的代码实现

1. 修改AppMainActivity

移除Activity中的普通状态变量和生命周期收集逻辑,在Composable内直接观察认证状态:

class AppMainActivity : ComponentActivity() {

    private val viewModel by viewModels<SplashViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        viewModel.onEvent(SplashEvent.CheckAuthentication)

        setContent {
            CarsLocalizerTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    val scaffoldState = rememberScaffoldState()
                    val navController = rememberNavController()
                    // 在Composable中收集StateFlow,状态变化自动触发重组
                    val userAuthState by viewModel.isAuthenticated.collectAsState()

                    Scaffold(
                        modifier = Modifier.fillMaxSize(),
                        scaffoldState = scaffoldState
                    ) {
                        val splash = installSplashScreen()
                        splash.setKeepOnScreenCondition {
                            userAuthState == UserAuthState.UNKNOWN
                        }

                        when (userAuthState) {
                            UserAuthState.UNAUTHENTICATED -> {
                                AuthNavigation(
                                    navController = navController,
                                    scaffoldState = scaffoldState,
                                    onLoginSuccess = {
                                        // 登录成功后通知ViewModel更新状态
                                        viewModel.onEvent(SplashEvent.SetAuthenticated(true))
                                    }
                                )
                            }
                            UserAuthState.AUTHENTICATED -> {
                                HomeScreen(
                                    viewModel = hiltViewModel(),
                                    onLogout = {
                                        // 登出后通知ViewModel更新状态
                                        viewModel.onEvent(SplashEvent.SetAuthenticated(false))
                                    }
                                )
                            }
                            UserAuthState.UNKNOWN -> {}
                        }
                    }
                }
            }
        }
    }
}

2. 更新SplashViewModel

添加手动更新认证状态的事件处理:

@HiltViewModel
class SplashViewModel @Inject constructor(
    private val authenticateUseCase: AuthenticateUseCase
): ViewModel() {

    private val _isAuthenticated = MutableStateFlow<UserAuthState>(value = UserAuthState.UNKNOWN)
    val isAuthenticated: StateFlow<UserAuthState> = _isAuthenticated.asStateFlow()

    fun onEvent(event: SplashEvent) {
        when (event) {
            is SplashEvent.CheckAuthentication -> {
                viewModelScope.launch {
                    val result = authenticateUseCase()
                    _isAuthenticated.emit(
                        if(result) UserAuthState.AUTHENTICATED 
                        else UserAuthState.UNAUTHENTICATED
                    )
                }
            }
            // 新增:手动设置认证状态的事件
            is SplashEvent.SetAuthenticated -> {
                _isAuthenticated.emit(
                    if(event.isAuthenticated) UserAuthState.AUTHENTICATED 
                    else UserAuthState.UNAUTHENTICATED
                )
            }
        }
    }
}

// 补充SplashEvent的完整定义
sealed class SplashEvent {
    object CheckAuthentication : SplashEvent()
    data class SetAuthenticated(val isAuthenticated: Boolean) : SplashEvent()
}

3. 修改AuthNavigation与LoginScreen

传递登录成功回调,在登录完成时触发状态更新:

@Composable
fun AuthNavigation(
    navController: NavHostController,
    scaffoldState: ScaffoldState,
    onLoginSuccess: () -> Unit // 新增登录成功回调
) {
    NavHost(
        navController = navController,
        startDestination = Screen.Login.route,
        modifier = Modifier.fillMaxSize()
    ) {
        composable(Screen.Login.route) {
            LoginScreen(
                onNavigate = { navController.navigate(it) },
                onLogin = {
                    navController.popBackStack()
                    onLoginSuccess() // 登录成功后通知上层更新状态
                },
                scaffoldState = scaffoldState,
                viewModel = hiltViewModel()
            )
        }
        // 其余注册/引导页代码保持不变
    }
}

4. 确认登出逻辑

确保HomeNavigation中的登出操作触发状态更新:

@Composable
fun HomeNavigation(
    navController: NavHostController,
    scaffoldState: ScaffoldState,
    onLogout: () -> Unit
) {
    NavHost(
        navController = navController,
        startDestination = Screen.Map.route
    ) {
        // 其余主功能页面代码保持不变
        composable(Screen.Logout.route) {
            LogoutDialogScreen(
                viewModel = hiltViewModel(),
                onLogout = {
                    navController.popBackStack()
                    onLogout() // 触发上层状态更新
                },
                onCancel = {
                    navController.popBackStack()
                }
            )
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 22:45:45