Типовая безопасность в 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() для определения объектов 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)
}

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

navController.navigate(Profile(id = 123))

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

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