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

SplashScreen API setKeepOnCondition失效:默认目标跳转异常

问题:启动页提前消失,LoginScreen短暂显示后才跳转主界面

我在MainActivity中需要读取DataStore的值来决定显示LoginScreen还是主界面,因此在调用onCreate()前启用了启动页。随后我使用runBlocking获取值并设置startDestination,预期启动页会在runBlocking执行期间保持显示,但实际启动页提前消失,LoginScreen短暂显示后才跳转到主界面。请问我遗漏了什么?是否只有LaunchedEffect的代码块被阻塞?

var isLoadingDataStoreTokens by remember { mutableStateOf(true) }
var startDestination : Destination by remember {
    mutableStateOf(
        LoginScreenDestination
    )
}
val tokenManager: AuthTokenManager by inject()

LaunchedEffect(Unit) {
    runBlocking {
        val authToken = tokenManager.getBearerToken().first()
        val isGuest = tokenManager.isGuest().first()
        startDestination =
            if (authToken != null && isGuest != null) DissertationsScreenDestination else LoginScreenDestination
        isLoadingDataStoreTokens = false
    }
}

splashScreen.setKeepOnScreenCondition {
    !isLoadingDataStoreTokens
}

问题原因

  1. runBlocking的错误使用:LaunchedEffect本身就是协程作用域,嵌套runBlocking会阻塞协程线程,导致状态更新延迟。同时,启动页的setKeepOnScreenCondition依赖状态判断,但线程阻塞会打乱状态更新的时序,使得启动页提前关闭。
  2. 初始导航的提前触发:startDestination初始值设为LoginScreenDestination,在DataStore读取完成前,导航组件已经先渲染了LoginScreen,后续状态更新只能触发二次跳转,因此出现闪屏。

解决方法

1. 移除runBlocking,直接在协程中挂起读取DataStore

DataStore的getBearerToken()和isGuest()返回Flow,直接用挂起函数first()读取即可,无需额外阻塞线程。

2. 延迟导航触发,避免初始页提前渲染

将startDestination初始设为null,直到DataStore读取完成后再赋值,确保加载期间导航组件不会渲染任何页面。

修改后的代码示例

var isLoadingDataStoreTokens by remember { mutableStateOf(true) }
var startDestination : Destination? by remember { mutableStateOf(null) }
val tokenManager: AuthTokenManager by inject()

LaunchedEffect(Unit) {
    val authToken = tokenManager.getBearerToken().first()
    val isGuest = tokenManager.isGuest().first()
    startDestination = if (authToken != null && isGuest != null) {
        DissertationsScreenDestination
    } else {
        LoginScreenDestination
    }
    isLoadingDataStoreTokens = false
}

splashScreen.setKeepOnScreenCondition {
    isLoadingDataStoreTokens // 加载状态持续时保持启动页显示
}

// 仅当目标页面确定后,才初始化导航
startDestination?.let { dest ->
    NavHost(navController = navController, startDestination = dest) {
        // 你的导航路由定义
    }
}

额外说明

  • setKeepOnScreenCondition的逻辑调整为isLoadingDataStoreTokens,直接明确“加载中就保持启动页”,避免原逻辑中取反带来的时序误解。
  • 初始startDestination设为null,彻底避免加载阶段的无效导航,确保启动页显示到加载完成后,直接跳转目标页面,消除闪屏问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 14:47:14