Compose导航:如何根据API响应动态修改启动页面?
基于登录API响应动态设置Jetpack Compose Destinations启动屏幕
核心思路
先在Activity中完成登录状态的API校验,根据响应结果动态指定导航的起始页面,同时处理加载、错误状态避免用户体验问题。
步骤1:管理登录状态与API请求
用ViewModel封装API请求和状态逻辑,确保配置变更时状态不丢失:
class AuthViewModel : ViewModel() { private val _authState = MutableStateFlow<AuthState>(AuthState.Loading) val authState: StateFlow<AuthState> = _authState init { checkAuthStatus() } fun checkAuthStatus() { viewModelScope.launch { _authState.value = AuthState.Loading try { // 替换为你的登录状态校验API调用 val apiResponse = AuthApi.checkUserAuth() _authState.value = if (apiResponse.isAuthenticated) { AuthState.Authenticated } else { AuthState.Unauthenticated } } catch (e: Exception) { _authState.value = AuthState.Error(e.message ?: "校验失败") } } } } sealed class AuthState { object Loading : AuthState() object Authenticated : AuthState() object Unauthenticated : AuthState() data class Error(val message: String) : AuthState() }
步骤2:在Activity中动态渲染导航
根据状态先显示加载/错误界面,API响应返回后再渲染指定起始页的导航宿主:
class MainActivity : ComponentActivity() { private val authViewModel: AuthViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { val authState by authViewModel.authState.collectAsStateWithLifecycle() when (authState) { AuthState.Loading -> { // 显示加载占位 Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { CircularProgressIndicator() } } AuthState.Authenticated -> { // 已登录,启动主页 DynamicNavHost(startDestination = HomeScreenDestination.route) } AuthState.Unauthenticated -> { // 未登录,启动登录页 DynamicNavHost(startDestination = LoginScreenDestination.route) } is AuthState.Error -> { // 错误状态,提供重试 Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Column(horizontalAlignment = Alignment.CenterHorizontally) { Text((authState as AuthState.Error).message) Button(onClick = { authViewModel.checkAuthStatus() }) { Text("重试") } } } } } } } }
步骤3:改造导航宿主支持动态起始页
修改默认的DestinationsNavHost,允许传入自定义起始页:
@Composable fun DynamicNavHost(startDestination: String) { val navController = rememberNavController() DestinationsNavHost( navController = navController, // 复制根导航图并替换起始页 navGraph = NavGraphs.root.copy(startDestination = startDestination) ) }
可选方案:初始化后跳转(避免修改导航图)
如果不想改动原导航图的start=true配置,可在导航初始化完成后根据状态跳转并清空返回栈:
@Composable fun DefaultNavHost(authViewModel: AuthViewModel) { val navController = rememberNavController() val authState by authViewModel.authState.collectAsStateWithLifecycle() // 监听状态变化执行跳转 DisposableEffect(authState) { when (authState) { AuthState.Authenticated -> { navController.navigate(HomeScreenDestination.route) { popUpTo(NavGraphs.root.startRoute) { inclusive = true } } } AuthState.Unauthenticated -> { navController.navigate(LoginScreenDestination.route) { popUpTo(NavGraphs.root.startRoute) { inclusive = true } } } else -> {} } onDispose {} } DestinationsNavHost( navController = navController, navGraph = NavGraphs.root ) }
关键注意点
- 优先用「先加载再渲染导航」的方式,避免默认起始页短暂显示后跳转的闪烁问题
- 跳转时必须清空返回栈(
popUpTo + inclusive=true),防止用户按返回键回到默认页面 - 处理API请求失败的边界情况,提供重试入口提升用户体验
内容的提问来源于stack exchange,提问作者Talha Akbar
相关产品推荐
相关产品推荐

