我正在使用 Jetpack Compose + Navigation(单一活动,无片段),并且我正在尝试执行如下导航路线:
SplashScreen---(延迟)---> AuthScreen---(如果成功)-->MainScreen
navigate()不幸的是,当我执行登录时,可组合项中的函数LoginScreen会导致无限循环。我不明白我是否正在触发重组或会发生什么。不幸的是,很难共享所有代码,但请记住:
LoginScreen可MainScreen组合项无关(您可以假设它们只是一个简单的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 …Run Code Online (Sandbox Code Playgroud) infinite-loop android-jetpack-navigation android-jetpack-compose
这是导致无限重组问题的代码
主要活动
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
val viewModel : MainViewModel by viewModel()
val state by viewModel.state.observeAsState()
NavHost(navController = navController, startDestination = "firstScreen") {
composable("firstScreen") { FirstScreen(
navigate = {
navController.navigate("secondScreen")
}, updateState = {
viewModel.getState()
},
state
)}
composable("secondScreen") { SecondScreen() }
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
视图模型
class MainViewModel : ViewModel() {
//var state = MutableStateFlow(0)
private val _state = MutableLiveData(0)
val state: LiveData<Int> = _state
fun …Run Code Online (Sandbox Code Playgroud) android kotlin android-jetpack-compose jetpack-compose-navigation compose-recomposition
在 Android 中,我经常想要导航以响应 ViewModel 的状态更改。(例如,成功的身份验证会触发导航到用户的主屏幕。)
最佳实践是从 ViewModel 内触发导航吗?是否有有意的机制来触发可组合项中的导航以响应 ViewModel 状态更改?
使用 Jetpack Compose 处理此用例的过程并不明显。如果我尝试类似以下示例的操作,将会发生导航,但我导航到的目的地将无法正常运行。我相信这是因为在调用导航之前不允许完成原始的可组合函数。
// Does not behave correctly.
@Composable fun AuthScreen() {
val screenState = viewModel.screenState.observeAsState()
if(screenState.value is ScreenState.UserAuthenticated){
navController.navigate("/gameScreen")
} else {
LoginScreen()
}
}
Run Code Online (Sandbox Code Playgroud)
如果我使用 LaunchedEffect ,我确实会观察到正确的行为,如下所示:
// Does behave correctly.
@Composable fun AuthScreen() {
val screenState = viewModel.screenState.observeAsState()
if(screenState.value is ScreenState.UserAuthenticated){
LaunchedEffect(key1 = "test") {
navController.navigate("$/gameScreen")
}
} else {
LoginScreen()
}
}
Run Code Online (Sandbox Code Playgroud)
它是否正确?LaunchedEffect 的文档说明如下,但我并不是 100% 清楚其含义:
当 LaunchedEffect 进入组合时,它将启动块到组合的 CoroutineContext 中。当 LaunchedEffect 用不同的 key1、key2 或 …
android android-jetpack-compose jetpack-compose-navigation compose-recomposition