Jetpack Compose + Navigation - navigate() 上的无限循环
Jetpack Compose + Navigation - Infinite loop on navigate()
我正在使用 Jetpack Compose + 导航(单个 Activity,无片段)并且我正在尝试执行如下导航路线:
SplashScreen
---(延迟)---> AuthScreen
---(如果成功)--> MainScreen
不幸的是,当我执行登录时,LoginScreen
可组合项中的函数 navigate()
导致无限循环。我不明白我是在触发重组还是发生了什么。
不幸的是,很难共享所有代码,但请记住:
- 这个问题似乎与
LoginScreen
和 MainScreen
可组合项无关(您可以假设它们只是一个简单的 Text
可组合项)
- 它似乎也与
NavigationGraph
无关。事实上,如果我只是进行 SplashScreen
--> MainScreen
转换,就不会出现问题
- 如果我删除行
navController.navigate("main")
就没有更多的循环;
- 代码基于(几乎是复制粘贴)this 示例
这是出现问题的 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)}
}
}
这是因为您正在尝试从可组合项进行导航。见 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.
例如您可以使用 LaunchEffect
我正在使用 Jetpack Compose + 导航(单个 Activity,无片段)并且我正在尝试执行如下导航路线:
SplashScreen
---(延迟)---> AuthScreen
---(如果成功)--> MainScreen
不幸的是,当我执行登录时,LoginScreen
可组合项中的函数 navigate()
导致无限循环。我不明白我是在触发重组还是发生了什么。
不幸的是,很难共享所有代码,但请记住:
- 这个问题似乎与
LoginScreen
和MainScreen
可组合项无关(您可以假设它们只是一个简单的Text
可组合项) - 它似乎也与
NavigationGraph
无关。事实上,如果我只是进行SplashScreen
-->MainScreen
转换,就不会出现问题 - 如果我删除行
navController.navigate("main")
就没有更多的循环; - 代码基于(几乎是复制粘贴)this 示例
这是出现问题的 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)}
}
}
这是因为您正在尝试从可组合项进行导航。见 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.
例如您可以使用 LaunchEffect