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

Jetpack Compose启动页实现问题:数据加载后跳转异常

如何在Jetpack Compose中正确实现启动页?

当前实现存在问题:应用启动后会先跳转到OnBoardingScreen,等ViewModel加载完数据后才重新跳转到HomeScreen。期望实现等待ViewModel数据加载完成后,再决定启动目标页面,该如何调整?

当前代码实现

NavHost(
    navController = navController,
    startDestination = determineStartDestination(viewModel),
    modifier = Modifier.fillMaxSize()
) {
    // 页面路由注册
}

private fun determineStartDestination(userModel: HomeViewModel): String {
    return if (userModel.homeState.value.emailFrom.isNotEmpty() && userModel.homeState.value.emailTo.isNotEmpty()) {
        OnHomeNav.getRoute()
    } else {
        OnBoardingScreenNav.getRoute()
    }
}

尝试过的无效方案

修改AndroidManifest设置启动主题:

android:theme="@style/Theme.MyApp.Starting"

在MainActivity中配置SplashScreen:

installSplashScreen().apply {
    setKeepOnScreenCondition {
        homeViewModel.homeState.value.emailFrom.isNotEmpty() && homeViewModel.homeState.value.emailTo.isNotEmpty()
    }
}
setContent { [...] }

启动页能正常显示,但setKeepOnScreenCondition逻辑未生效,仍会出现:启动页→OnBoardingScreen(显示1秒)→HomeScreen的流程。

临时但不可接受的解决方案

通过delay()等待状态更新,本质是依赖不可靠的时间延迟:

init {
    viewModelScope.launch {
        getUser()
    }
}

// 修改前的getUser方法
private fun getUser() {
    viewModelScope.launch {
        userRepository.getUser().collectLatest { userModel ->
            homeState.update {
                copy(
                    userModel = userModel,
                    nameAndSurname = userModel?.nameAndSurname ?: "",
                    number = userModel?.phoneNumber ?: "",
                    email = userModel?.email ?: "",
                    registrationNumber = userModel?.registrationNumber ?: "",
                    emailTo = userModel?.emailTo ?: "",
                    emailFrom = userModel?.emailFrom ?: ""
                )
            }
        }
    }
}

// 修改后的getUser方法
private fun getUser() {
    viewModelScope.launch {
        userRepository.getUser().filterNotNull().collectLatest { userModel ->
            homeState.update {
                copy(
                    userModel = userModel,
                    nameAndSurname = userModel?.nameAndSurname ?: "",
                    number = userModel?.phoneNumber ?: "",
                    email = userModel?.email ?: "",
                    registrationNumber = userModel?.registrationNumber ?: "",
                    emailTo = userModel?.emailTo ?: "",
                    emailFrom = userModel?.emailFrom ?: ""
                )
            }
            delay(100L)
            checkIfUserIsLoggedIn()
        }
    }
}

问题根源:错误依赖时间延迟来等待状态更新,而非通过可靠的状态标记判断加载完成。


正确实现方案

核心思路:通过ViewModel维护加载状态,配合系统SplashScreen API,确保启动页显示到数据加载完成,再根据最终状态决定跳转目标。

1. 修正ViewModel逻辑,添加加载状态标记

在ViewModel中新增isLoading状态,初始为true,数据加载完成后切换为false,确保状态更新的可靠性:

class HomeViewModel(private val userRepository: UserRepository) : ViewModel() {
    private val _homeState = MutableStateFlow(HomeState())
    val homeState = _homeState.asStateFlow()

    // 新增加载状态标记
    private val _isLoading = MutableStateFlow(true)
    val isLoading = _isLoading.asStateFlow()

    init {
        getUser()
    }

    private fun getUser() {
        viewModelScope.launch {
            try {
                userRepository.getUser()
                    .filterNotNull()
                    .collectLatest { userModel ->
                        _homeState.update {
                            copy(
                                userModel = userModel,
                                nameAndSurname = userModel.nameAndSurname ?: "",
                                number = userModel.phoneNumber ?: "",
                                email = userModel.email ?: "",
                                registrationNumber = userModel.registrationNumber ?: "",
                                emailTo = userModel.emailTo ?: "",
                                emailFrom = userModel.emailFrom ?: ""
                            )
                        }
                    }
            } finally {
                // 无论是否获取到用户数据,加载完成后都标记为非加载状态
                _isLoading.value = false
            }
        }
    }
}

data class HomeState(
    val userModel: UserModel? = null,
    val nameAndSurname: String = "",
    val number: String = "",
    val email: String = "",
    val registrationNumber: String = "",
    val emailTo: String = "",
    val emailFrom: String = ""
)

2. 正确配置SplashScreen,基于加载状态控制显示

在MainActivity中,用isLoading控制启动页的显示时长,确保数据加载完成后再进入目标页面:

class MainActivity : ComponentActivity() {
    private val homeViewModel by viewModels<HomeViewModel>()

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

        installSplashScreen().apply {
            setKeepOnScreenCondition {
                // 只要加载未完成,就保持启动页显示
                homeViewModel.isLoading.value
            }
        }

        setContent {
            MyAppTheme {
                val navController = rememberNavController()
                // 收集加载完成后的最终状态
                val homeState by homeViewModel.homeState.collectAsState()

                NavHost(
                    navController = navController,
                    // 此时数据已加载完成,可正确判断启动目标
                    startDestination = determineStartDestination(homeState),
                    modifier = Modifier.fillMaxSize()
                ) {
                    composable(OnBoardingScreenNav.getRoute()) {
                        OnBoardingScreen()
                    }
                    composable(OnHomeNav.getRoute()) {
                        HomeScreen()
                    }
                }
            }
        }
    }

    private fun determineStartDestination(homeState: HomeState): String {
        return if (homeState.emailFrom.isNotEmpty() && homeState.emailTo.isNotEmpty()) {
            OnHomeNav.getRoute()
        } else {
            OnBoardingScreenNav.getRoute()
        }
    }
}

方案说明

  • 之前的SplashScreen方案失效原因:初始状态下emailFrom和emailTo为空,导致setKeepOnScreenCondition直接返回false,启动页提前消失,此时数据还在加载中。
  • 新方案通过isLoading状态精准控制启动页显示时长,确保数据加载完成后,NavHost才能获取到最新的homeState,从而正确判断启动目标页面。
  • 无需依赖delay(),状态更新是同步可靠的,避免了时间延迟带来的不确定性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:33:19