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

如何在Jetpack Compose的Activity的onStart中实现页面导航?

解决Jetpack Compose中已登录用户自动导航至首页的问题

在Compose的单Activity架构下,无需再用StartActivity()跳转页面,而是通过Navigation Compose导航组件配合状态管理实现页面切换。核心思路是让登录状态成为可观察的数据源,导航组件根据状态自动完成跳转。

步骤1:创建登录状态ViewModel

用ViewModel持有登录状态,确保状态能在Activity和可组合项间共享,且生命周期稳定:

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class AuthViewModel : ViewModel() {
    // 私有可变状态,仅在ViewModel内修改
    private val _isUserLoggedIn = MutableStateFlow(false)
    // 公开只读状态,供外部观察
    val isUserLoggedIn: StateFlow<Boolean> = _isUserLoggedIn

    // 更新登录状态
    fun updateLoginStatus(isLoggedIn: Boolean) {
        viewModelScope.launch {
            _isUserLoggedIn.emit(isLoggedIn)
        }
    }
}

步骤2:修改MainActivity集成ViewModel

在Activity中初始化ViewModel,在onStart检查登录状态并更新ViewModel,同时在登录成功后同步状态:

class MainActivity : ComponentActivity() {
    lateinit var mGoogleSignInClient: GoogleSignInClient
    private lateinit var signInLauncher: ActivityResultLauncher<Intent>
    // 初始化AuthViewModel
    private val authViewModel by viewModels<AuthViewModel>()

    override fun onStart() {
        super.onStart()
        val account = GoogleSignIn.getLastSignedInAccount(this)
        // 更新ViewModel的登录状态
        authViewModel.updateLoginStatus(account != null)
        account?.email?.let { Log.d("Signed In: ", it) }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestEmail()
            .build()

        mGoogleSignInClient = GoogleSignIn.getClient(this, gso)

        signInLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            val task = GoogleSignIn.getSignedInAccountFromIntent(result.data)
            handleSignInResult(task)
        }

        super.onCreate(savedInstanceState)

        setContent {
            // 将ViewModel传递给导航组件
            Navigation(
                authViewModel = authViewModel,
                mGoogleSignInClient = mGoogleSignInClient,
                signInLauncher = signInLauncher
            )
        }
    }

    private fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) {
        try {
            val account = completedTask.getResult(ApiException::class.java)
            // 登录成功后更新状态
            authViewModel.updateLoginStatus(true)
            val idToken = account.idToken
        } catch (e: ApiException) {
            Log.w("Sign In Error", "signInResult:failed code=" + e.statusCode)
            Toast.makeText(this, "Sign in failed", Toast.LENGTH_SHORT).show()
        }
    }
}

步骤3:完善Navigation组件,根据状态自动导航

先定义路由:

sealed class Screens(val route: String) {
    object LoginScreen : Screens("login_screen")
    object UserHomeScreen : Screens("user_home_screen")
}

再编写导航可组合项,监听登录状态变化自动跳转:

import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController

@Composable
fun Navigation(
    authViewModel: AuthViewModel,
    mGoogleSignInClient: GoogleSignInClient,
    signInLauncher: ActivityResultLauncher<Intent>
) {
    val navController = rememberNavController()
    val isLoggedIn = authViewModel.isUserLoggedIn.collectAsState()

    // 监听登录状态变化,自动触发导航
    LaunchedEffect(isLoggedIn.value) {
        if (isLoggedIn.value) {
            // 跳转到首页并清空返回栈,防止返回登录页
            navController.navigate(Screens.UserHomeScreen.route) {
                popUpTo(Screens.LoginScreen.route) { inclusive = true }
            }
        } else {
            // 未登录时跳转到登录页
            navController.navigate(Screens.LoginScreen.route) {
                popUpTo(Screens.UserHomeScreen.route) { inclusive = true }
            }
        }
    }

    NavHost(navController = navController, startDestination = Screens.LoginScreen.route) {
        composable(Screens.LoginScreen.route) {
            LoginScreen(
                mGoogleSignInClient = mGoogleSignInClient,
                signInLauncher = signInLauncher
            )
        }
        composable(Screens.UserHomeScreen.route) {
            UserHomeScreen()
        }
    }
}

// 示例登录页面
@Composable
fun LoginScreen(
    mGoogleSignInClient: GoogleSignInClient,
    signInLauncher: ActivityResultLauncher<Intent>
) {
    Button(onClick = {
        val signInIntent = mGoogleSignInClient.signInIntent
        signInLauncher.launch(signInIntent)
    }) {
        Text(text = "Google登录")
    }
}

// 示例首页
@Composable
fun UserHomeScreen() {
    Text(text = "欢迎来到首页!")
}

关键说明

  • 状态管理:用ViewModel的StateFlow持有登录状态,确保配置变化(如屏幕旋转)时状态不丢失,且可被可组合项观察。
  • 导航触发:LaunchedEffect会在isLoggedIn值变化时执行,自动完成导航,避免在Activity中直接操作导航控制器。
  • 返回栈处理:popUpTo配合inclusive = true,确保跳转后无法返回之前的页面,符合登录后的预期行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 05:39:54