Безопасная навигация в Jetpack Compose – использование навигации

Вопрос или проблема

Я всё ещё учусь Jetpack Compose и сейчас пытаюсь перейти с маршрутизации на основе строк на новые API, следуя этой статье.

Ранее я использовал что-то вроде:


@Composable
fun HomeScreen(
   ...
   navHostController: NavHostController
   ...
) {
...
   if (state.logoutRequired) {
       navController.navigate(Screen.Auth)
    }
...
}

в своих композируемых экранах. Теперь это приводит к пропускам кадров и визуальным сбоям при навигации. Я решаю эту проблему, используя LaunchedEffect, но всё ещё не понял, почему это так работает.

Почему я могу навигировать из LaunchedEffect, onClick, onDismiss, из других функций обратного вызова, но не могу из тела композируемых функций?

Ответ или решение

Вопрос, который вы подняли, касается управления навигацией в Jetpack Compose, особенно в контексте использования безопасной навигации на основе типов. Давайте разберемся с тем, почему использование LaunchedEffect для навигации является правильным подходом, в отличие от выполнения навигации прямо в теле коммопозиций.

Проблема с навигацией в теле составного компонента

Когда вы вызываете navController.navigate(Screen.Auth) непосредственно в теле составного компонента, это приводит к тому, что навигация выполняется каждый раз, когда происходит повторный состав (recomposition). Это может происходить из-за изменения состояния, например, когда state.logoutRequired становится истинным. В результате ваши функции UI могут срабатывать множество раз, что приводит к визуальным сбоям и "скачкам" кадров, поскольку система пытается обработать множество действий навигации в рамках одного цикла композиции.

Почему LaunchedEffect работает лучше

LaunchedEffect – это вспомогательная функция, которая позволяет вам запускать эффекты, привязанные к жизненному циклу вашего составного компонента. Когда вы используете LaunchedEffect, вы гарантируете, что навигация будет вызвана только один раз, когда определённый ключ (в данном случае state.logoutRequired) изменяется. Это предотвращает навигацию на каждом повторном выполнении и избавляет от навигационных конфликтов и ошибок.

Пример использования LaunchedEffect:

@Composable
fun HomeScreen(
   ...
   navController: NavHostController,
   ...
) {
    val state = // Получение состояния

    LaunchedEffect(state.logoutRequired) {
        if (state.logoutRequired) {
            navController.navigate(Screen.Auth)
        }
    }

    // Остальная часть UI
}

Почему важно использовать побочные эффекты

Использование LaunchedEffect и других механик, таких как SideEffect, помогает вам лучше управлять побочными эффектами, которые могут быть связаны с состоянием приложения или взаимодействиями пользователя. Это позволяет избежать пенальти производительности и проблем с пользовательским интерфейсом, которые появляются при неосторожном использовании навигации в теле составного компонента.

Заключение

Резюмируя, для избежания визуальных артефактов и сбоев при навигации в Jetpack Compose рекомендуется всегда использовать LaunchedEffect (или другие подходящие механизмы) для запуска действий навигации в ответ на изменения состояния. Таким образом, вы можете гарантировать, что навигация происходит только тогда, когда это необходимо, а не на каждом перерисовке вашего компонента. Это даст вашему приложению более стабильный и предсказуемый опыт работы.

Оцените материал
Добавить комментарий

Капча загружается...