Безопасность типов в Kotlin DSL и Navigation Compose

Вы можете использовать встроенные API с безопасностью типов, чтобы обеспечить безопасность типов во время компиляции для графа навигации. Эти API доступны, если в приложении используется Navigation Compose или Navigation Kotlin DSL. Они доступны с Navigation 2.8.0.

Эти API выполняют те же функции, что и Safe Args для графов навигации, созданных с помощью XML.

Как задать маршруты

Чтобы использовать маршруты с безопасной типизацией в Compose, сначала нужно определить сериализуемые классы или объекты, представляющие маршруты.

Чтобы определить сериализуемые объекты, используйте аннотацию @Serializable, предоставленную плагином Kotlin Serialization. Чтобы добавить этот плагин в проект, добавьте следующие зависимости.

Чтобы выбрать тип маршрута, следуйте приведенным ниже правилам.

  • Объект. Используйте объект для маршрутов без аргументов.
  • Класс. Используйте класс или класс данных для маршрутов с аргументами.
  • KClass<T> – используется, если не нужно передавать аргументы, например для класса без параметров или класса, в котором все параметры имеют значения по умолчанию.
    1. Пример: Profile::class

В любом случае объект или класс должен быть сериализуемым.

Пример:

// Define a home route that doesn't take any arguments
@Serializable
object Home

// Define a profile route that takes an ID
@Serializable
data class Profile(val id: String)

Как построить график

Затем вам нужно определить граф навигации. Используйте функцию composable(), чтобы определить компонуемые функции как пункты назначения в графе навигации.

NavHost(navController, startDestination = Home) {
     composable<Home> {
         HomeScreen(onNavigateToProfile = { id ->
             navController.navigate(Profile(id))
         })
     }
     composable<Profile> { backStackEntry ->
         val profile: Profile = backStackEntry.toRoute()
         ProfileScreen(profile.id)
     }
}

Обратите внимание на следующее:

  • composable() принимает параметр типа. То есть composable<Profile>.
  • Определение типа целевой страницы – более надежный подход, чем передача route строки, как в composable("profile").
  • Класс маршрута определяет тип каждого аргумента навигации, как в val id: String, поэтому нет необходимости использовать NavArgument.
  • Для маршрута профиля метод расширения toRoute() воссоздает объект Profile из объекта NavBackStackEntry и его аргументов.

Подробнее о том, как создать граф, рассказывается на странице Как спроектировать граф навигации.

Как получить доступ к аргументам в ViewModel

Чтобы получить аргументы из маршрута с безопасностью типов в ViewModel, можно извлечь маршрут из SavedStateHandle, вызвав SavedStateHandle.toRoute<T>(), где T – класс маршрута:

class ProfileViewModel(
    savedStateHandle: SavedStateHandle
) : ViewModel() {
    private val profile = savedStateHandle.toRoute<Profile>()
    private val userInfo: Flow<UserInfo> = userInfoRepository.getUserInfo(profile.id)
}

Наконец, вы можете перейти к composable-функции, используя функцию navigate(), передав ей экземпляр маршрута:

navController.navigate(Profile(id = 123))

Пользователь переходит к пункту назначения composable<Profile> в графе навигации. Любые аргументы навигации, например id, можно получить, воссоздав Profile с помощью NavBackStackEntry.toRoute и прочитав его свойства.

Дополнительные ресурсы