안녕하세요. 취준생때 글을 자주 작성하다가 카카오쪽에 취업 후 만 2년이 조금 넘는 경력이 쌓이고 소홀했던 블로그에 오랜만에 포스팅을 해보려고 합니다.
이 글을 보러 오신분들이라면 compose 또는 fragment의 navigation을 사용해보신 분들이라고 생각합니다. 이 글에서는 navigation에 대한 설명은 자세히 하지 않을 것이며 변경사항이 많은 2.8.0-alpha08 버전에 대해 알아보려고 합니다.
먼저, 2.8.0-alpha08버전에 어떤것들이 변경되었는지 문서로 살펴보겠습니다.

// Define a home destination that doesn't take any arguments
@Serializable
object Home
// Define a profile destination that takes an ID
@Serializable
data class Profile(val id: String)
// Now define your NavHost using type safe objects
NavHost(navController, startDestination = Home) {
composable<Home> {
HomeScreen(onNavigateToProfile = { id ->
navCeontroller.navigate(Profile(id))
})
}
composable<Profile> { backStackEntry ->
val profile: Profile = backStackEntry.toRoute()
ProfileScreen(profile)
}
}
@Serializable 어노테이션이 붙은 object, data class를 composable의 Route로 받을 수 있도록 구현되어 있네요. 그리고 NavBackStackEntry 객체에서 직접 arguments?.getString()과 같이 argument를 꺼내지 않고, toRoute()라는 확장함수를 제공하여 그대로 Profile 객체 형태로 타입 안정성을 지키면서 사용할 수 있게 되었습니다.public inline fun <reified T : Any> NavGraphBuilder.composable(
typeMap: Map<KType, @JvmSuppressWildcards NavType<*>> = emptyMap(),
deepLinks: List<NavDeepLink> = emptyList(),
noinline enterTransition:
(AnimatedContentTransitionScope<NavBackStackEntry>.() -> @JvmSuppressWildcards
EnterTransition?)? =
null,
noinline exitTransition:
(AnimatedContentTransitionScope<NavBackStackEntry>.() -> @JvmSuppressWildcards
ExitTransition?)? =
null,
noinline popEnterTransition:
(AnimatedContentTransitionScope<NavBackStackEntry>.() -> @JvmSuppressWildcards
EnterTransition?)? =
enterTransition,
noinline popExitTransition:
(AnimatedContentTransitionScope<NavBackStackEntry>.() -> @JvmSuppressWildcards
ExitTransition?)? =
exitTransition,
noinline sizeTransform:
(AnimatedContentTransitionScope<NavBackStackEntry>.() -> @JvmSuppressWildcards
SizeTransform?)? =
null,
noinline content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit
)
뭔가 많이 변경됐는데요 먼저 제네릭으로 받은 타입의 클래스의 타입을 코틀린 리플렉션 KClass형태로 전달하여 이것을 Route로써 사용하고 있습니다.

그럼 ComposeNavigatorDestinationBuilder에 어떤 생성자가 추가됐는지 보겠습니다.
// 기존 생성자
public constructor(
navigator: ComposeNavigator,
route: String,
content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit
) : super(navigator, route) {
this.composeNavigator = navigator
this.content = content
}
// 새롭게 추가된 생성자
public constructor(
navigator: ComposeNavigator,
route: KClass<*>,
typeMap: Map<KType, @JvmSuppressWildcards NavType<*>>,
content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit
) : super(navigator, route, typeMap) {
this.composeNavigator = navigator
this.content = content
}
String 값을 받는 생성자가 존재하고, KClass<*> 형태로 받는 생성자가 추가됐네요
@Serializable
@Parcelize
data class SearchParameters(
val searchQuery: String,
val filters: List<String>
)
val SearchParametersType = object : NavType<SearchParameters>(
isNullableAllowed = false
) {
override fun put(bundle: Bundle, key: String, value: SearchParameters) {
bundle.putParcelable(key, value)
}
override fun get(bundle: Bundle, key: String): SearchParameters {
return bundle.getParcelable(key) as SearchParameters
}
override fun serializeAsValue(value: SearchParameters): String {
// Serialized values must always be Uri encoded
return Uri.encode(Json.encodeToString(value))
}
override fun parseValue(value: String): SearchParameters {
// Navigation takes care of decoding the string
// before passing it to parseValue()
return Json.decodeFromString<SearchParameters>(value)
}
}
typeMap = mapOf(typeOf<SearchParameters>() to SearchParametersType)
저는 Navigation Kotlin DSL을 사용해보진 않았지만 Compose와 동일한 형태로 사용할 수 있다고 하네요
혹시 Navigation Kotlin DSL 이나 Navigation Compose를 사용하시는 분들이라면 안정화 버전이 출시된 이후에 한번 사용해보는것도 괜찮을 것 같습니다
다음엔 Navigation Kotlin DSL에 대해 포스팅해보겠습니다