Почему вид продолжает мигать при использовании навигации по jetpack с помощью Compose?

#android #kotlin #android-jetpack-compose #android-jetpack-navigation

Вопрос:

У меня есть экран входа в систему, и когда вход в систему будет успешным, а модель представления обновит переменную изменяемого состояния, я ожидаю, что будет вызвана новая составная функция для отображения нового экрана, а вход в систему будет удален. Проблема в том, что при отображении нового экрана (он же Screen.AccountsScreen ) его содержимое продолжает мигать/перерисовываться, и то же самое происходит с формой входа в систему, которая никогда не уничтожается (я знаю это, потому что сообщение журнала «Переназначение…» печатается бесконечно). Я предполагаю, что это происходит, потому isLoginSuccessful что состояние всегда истинно. Кажется, мне нужно событие, которое можно использовать только один раз, это правильно? Если да, то как я могу это сделать?

LoginViewModel.kt

 @HiltViewModel
class LoginViewModel @Inject constructor() : ViewModel() {

  var isLoginSuccessful by mutableStateOf(false)
  var errorMessage by mutableStateOf("")
  
  fun onLoginClick(email: String, password:String) {
    errorMessage = ""
    if (credentialsValid(email, password)) {
      isLoginSuccessful = true
    } else {
      errorMessage = "Email or password invalid"
      isLoginSuccessful = false
    }
  }
}
 

LoginScreen.kt

 @Composable
fun loginScreen(
  navController: NavController,
  viewModel: LoginViewModel = hiltViewModel()
) {
  println("Recomponing...")
  // Here gos the code for the login form
  
  if (viewModel.isLoginSuccessful) {
    navController.navigate(Screen.AccountsScreen.route) {
      popUpTo(Screen.LoginScreen.route) { inclusive = true }
    }
  }
}
 

Комментарии:

1. Привет! Мой ответ решил ваш вопрос? Если да, пожалуйста, примите это, поставив галочку под счетчиком голосов. В противном случае, дайте мне знать, если у вас возникнут какие-либо проблемы с этим.

Ответ №1:

Составная навигация перестраивает как исчезающие, так и появляющиеся представления во время перехода. Это ожидаемое поведение.

Вы вызываете навигацию при каждой перестановке. Ваша проблема заключается в этих строках:

 if (viewModel.isLoginSuccessful) {
    navController.navigate(Screen.AccountsScreen.route) {
        popUpTo(Screen.LoginScreen.route) { inclusive = true }
    }
}
 

Вы не должны изменять состояние непосредственно из конструкторов представлений. В этом случае LaunchedEffect следует использовать:

 if (viewModel.isLoginSuccessful) {
    LaunchedEffect(Unit) {
        navController.navigate(Screen.AccountsScreen.route) {
            popUpTo(Screen.LoginScreen.route) { inclusive = true }
        }
    }
}
 

Ознакомьтесь с дополнительной документацией по побочным эффектам.