Jetpack Compose +导航 - 导航()上的无限循环

发布于 2025-01-09 14:07:54 字数 2905 浏览 1 评论 0原文

我正在使用 Jetpack Compose + 导航(单一活动,无片段),并且我正在尝试执行如下导航路线:

SplashScreen ---(delay)---> AuthScreen ---(如果成功)--> MainScreen

不幸的是,当我执行登录时,LoginScreen 可组合项中的函数 navigate() 会导致无限循环。我不明白我是否正在触发重组或会发生什么。 不幸的是,很难共享所有代码,但请记住:

  • 该问题似乎与 LoginScreenMainScreen 可组合项无关(您可以假设它们是只是一个简单的 Text 可组合项)
  • 它似乎也与 NavigationGraph 无关。事实上,如果我只是制作 SplashScreen --> MainScreen 转换不会发生问题
  • 如果我删除行 navController.navigate("main") ,则不再有循环;
  • 该代码基于(几乎复制粘贴) 示例

这是出现问题的 AuthScreen 代码。

@Composable
fun AuthScreen(navController: NavController) {
    val signInRequestCode = 1
    val context = LocalContext.current

    val mSignInViewModel: SignInGoogleViewModel = viewModel(
        factory = SignInGoogleViewModelFactory(context.applicationContext as Application)
    )

    val state = mSignInViewModel.googleUser.observeAsState()
    val user = state.value

    val isError = rememberSaveable { mutableStateOf(false) }


    val authResultLauncher =
        rememberLauncherForActivityResult(contract = GoogleApiContract()) { task ->
            try {
                val gsa = task?.getResult(ApiException::class.java)

                if (gsa != null) {
                    mSignInViewModel.fetchSignInUser(gsa.email, gsa.displayName)
                } else {
                    isError.value = true
                }
            } catch (e: ApiException) {
                Log.e("Authscreen", e.toString())
            }
        }

    AuthView(
        onClick = { authResultLauncher.launch(signInRequestCode) },
        isError = isError.value,
        mSignInViewModel
    )

    Log.d("TEST", "Loop check")  //THIS GOES LIKE CRAZY IN THE LOGCAT!

    user?.let {
        mSignInViewModel.hideLoading()

        //Create JSON adapter to move data
        val moshi = Moshi.Builder().build()
        val jsonAdapter = moshi.adapter(GoogleUserModel::class.java).lenient()
        val userJson = jsonAdapter.toJson(user)

        //Navigate to main screen
        navController.navigate("main")
    }

}

这是导航图代码:

const val ROOT_ROUTE = "root_route"

@Composable
fun SetupRootNavGraph(navController: NavHostController) {
    NavHost(
        navController = navController,
        startDestination = Screen.SplashScreen.route,
        route = ROOT_ROUTE
    ) {
        composable(Screen.SplashScreen.route) { SplashScreen(navController)}
        composable(Screen.AuthScreen.route) { AuthScreen(navController)}
        composable(Screen.MainScreen.route) {MainScreen(navController)}
    }
}

I'm using Jetpack Compose + Navigation (Single Activity, no Fragments) and i'm trying to perform a navigation route as follow:

SplashScreen ---(delay)---> AuthScreen ---(if successful)--> MainScreen

Unfortunately, when i perform Login, the function navigate() in the LoginScreen composables causes an infinite loop. I don't understand if i'm triggering recomposition or what happens.
Unfortunately, it's hard to share all the code, but keep in mind that:

  • the issue doesn't seem to be related to LoginScreen and MainScreen composables (you can assume them to be just a simple Text composable)
  • It doesn't seem to be related to NavigationGraph too. Infact, if i just make the SplashScreen --> MainScreen transition there is no problem occurring
  • If i remove the line navController.navigate("main") there is no more loop;
  • The code is based (almost copy-paste) of this example

This is the AuthScreen code where the issue occurs.

@Composable
fun AuthScreen(navController: NavController) {
    val signInRequestCode = 1
    val context = LocalContext.current

    val mSignInViewModel: SignInGoogleViewModel = viewModel(
        factory = SignInGoogleViewModelFactory(context.applicationContext as Application)
    )

    val state = mSignInViewModel.googleUser.observeAsState()
    val user = state.value

    val isError = rememberSaveable { mutableStateOf(false) }


    val authResultLauncher =
        rememberLauncherForActivityResult(contract = GoogleApiContract()) { task ->
            try {
                val gsa = task?.getResult(ApiException::class.java)

                if (gsa != null) {
                    mSignInViewModel.fetchSignInUser(gsa.email, gsa.displayName)
                } else {
                    isError.value = true
                }
            } catch (e: ApiException) {
                Log.e("Authscreen", e.toString())
            }
        }

    AuthView(
        onClick = { authResultLauncher.launch(signInRequestCode) },
        isError = isError.value,
        mSignInViewModel
    )

    Log.d("TEST", "Loop check")  //THIS GOES LIKE CRAZY IN THE LOGCAT!

    user?.let {
        mSignInViewModel.hideLoading()

        //Create JSON adapter to move data
        val moshi = Moshi.Builder().build()
        val jsonAdapter = moshi.adapter(GoogleUserModel::class.java).lenient()
        val userJson = jsonAdapter.toJson(user)

        //Navigate to main screen
        navController.navigate("main")
    }

}

This is the Navigation Graph code:

const val ROOT_ROUTE = "root_route"

@Composable
fun SetupRootNavGraph(navController: NavHostController) {
    NavHost(
        navController = navController,
        startDestination = Screen.SplashScreen.route,
        route = ROOT_ROUTE
    ) {
        composable(Screen.SplashScreen.route) { SplashScreen(navController)}
        composable(Screen.AuthScreen.route) { AuthScreen(navController)}
        composable(Screen.MainScreen.route) {MainScreen(navController)}
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

み格子的夏天 2025-01-16 14:07:54

这是因为您正在尝试从可组合项进行导航。请参阅文档

您应该仅将 navigator() 作为回调的一部分调用,而不是作为可组合项本身的一部分,以避免在每次重组时调用 navigator()。

例如,您可以使用 LaunchEffect

It's because you're trying to navigate from a composable. See the documentation

You should only call navigate() as part of a callback and not as part of your composable itself, to avoid calling navigate() on every recomposition.

You could use a LaunchEffect for instance

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文