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
相关产品推荐
相关产品推荐

