Logo picture
NiNyYoon

Compose Navigation2 간단하게 살펴보기

November 26, 2025

Compose Navigation2

안드로이드 애플리케이션을 개발할 때 화면 이동(Navigation) 은 사용자 경험의 핵심 요소입니다.
Compose 에서 화면 이동(Navigation)을 구현할 때, 사용자가 직접 화면에 대한 상태(State) 를 정의하고 이 상태 값을 변경하여 화면을 노출 시켜줄 수도 있지만, 이처럼 직접 구현하게 되면 상태 저장, 생명주기 관리, 백 스택 관리 등 고려해야 할 점이 복잡하게 늘어납니다. (viewModel 을 사용할 경우 ViewModelStoerOwner 의 구현 등)
그러므로 Compose 에서는 네비게이션을 쉽게 사용하기 위해 공식 navigation-compose 라이브러리를 사용합니다.
지금 부터 Comopse Navigation 의 기본적인 개념과 간단한 예시를 통해 라이브러리를 이해해 보도록 하겠습니다.

본 내용은 Navigation2 에 대한 간략한 개념/사용법을 소개하며, Navigation3 는 추후 포스트에서 Navigation2 와 비교하면서 다루도록 하겠습니다.

Compose Navigation 의 핵심 가치

1. Type-safe (타입 안전성)

가장 큰 장점 중 하나입니다. 기존에는 화면 간 데이터(인자)를 전달할 때 String이나 Bundle을 사용하여 타입 오류가 발생하기 쉬웠습니다. 하지만 Compose Navigation은 Route 정의 시 인자의 타입을 명시할 수 있게 되어, 잘못된 타입의 데이터를 전달하려는 시도를 컴파일 시점에 잡아낼 수 있습니다.

2. 상태 주도 (State-driven)

Compose의 철학을 그대로 따릅니다. 화면 이동을 명령(Imperative)하는 것이 아니라, 내비게이션 상태(State)가 변경되면 그에 따라 화면(UI)이 자동으로 갱신됩니다. 이는 내비게이션 로직을 더욱 직관적이고 예측 가능하게 만듭니다.

3. 단일 활동 아키텍처 (Single-Activity Architecture)

Compose 앱은 모든 화면을 단일 Activity 내의 여러 Composable로 구성하는 것이 권장됩니다. Compose Navigation은 이 단일 Activity 내에서 여러 화면 컴포저블 간의 전환을 효율적으로 관리하여, 앱의 복잡성을 줄이고 성능을 개선하는 데 기여합니다.

Library Settings

Navigation 2 사용

dependencies {
    val nav_version = "2.9.6"

    implementation("androidx.navigation:navigation-compose:$nav_version")
}

Compose Navigation 핵심 요소

이해를 위해 먼저 예제 코드를 확인해 보겠습니다.

// HomeScreen 컴포저블
@Composable
fun HomeScreen(
    onNavigateToDetail: (itemId: Int) -> Unit,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(text = "Home Screen", style = MaterialTheme.typography.headlineLarge)
        Spacer(modifier = Modifier.height(16.dp))
        Button(onClick = {
            // 버튼 클릭 이벤트 발생 -> 콜백 함수 호출 (상위 컴포저블에 네비게이션 요청)
            val itemId = 456
            onNavigateToDetail(itemId)
        }) {
            Text("Go to Detail (ID: 456)")
        }
    }
}

// DetailScreen 컴포저블
@Composable
fun DetailScreen(itemId: Int) {
    // ... DetailScreen 내용 ...
    Text(text = "Received Item ID: $itemId")
}

// Route: Home 화면 Route (인자가 없으면 빈 클래스)
@Serializable
object HomeRoute

// Route: Detail 화면 Route (인자는 클래스의 속성으로 정의)
@Serializable
data class DetailRoute(val itemId: Int)

// NavHost를 포함하는 메인 컴포저블
@Composable
fun AppNavigationTypeSafe() {
    // ⬅️ 핵심 요소 1: NavController 생성 및 상태 저장 (네비게이션 엔진)
    val navController = rememberNavController()
    
    // ⬅️ 핵심 요소 2: 요소 2: NavHost - 네비게이션 영역 및 목적지(Route) 등록 컨테이너
    NavHost(
        navController = navController, 
        startDestination = HomeRoute
    ) {

        // Home 화면 등록
        composable<HomeRoute> {
            HomeScreen(
                // ⬅️ onNavigateToDetail 콜백 함수 정의
                onNavigateToDetail = { itemId ->
                    // 콜백이 호출되면, navController를 사용하여 실제 이동 실행
                    navController.navigate(DetailRoute(itemId = itemId))
                }
            )
        }

        // Detail 화면 등록 (DetailRoute 인자를 toRoute<T>()로 타입 안전하게 추출)
        composable<DetailRoute> { backStackEntry ->
            val route = backStackEntry.toRoute<DetailRoute>()
            DetailScreen(itemId = route.itemId)
        }
    }
}

위 코드를 실무에서 쓰기에도 충분하겠지만 조금더 현대적인 네비게이션 구성을 확인하려면 Now in Android 코드를 참고해 보시는길 추천드립니다.

핵심요소1. NavController (네비게이션 컨트롤러)

NavController 는 네비게이션을 실제로 제어하고 관리하는 핵심 객체입니다.

역할: 화면 전환(Navigation), 뒤로 가기(Pop), Back Stack(백 스택) 관리 등 모든 네비게이션 작업을 처리하는 네비게이션 엔진입니다.

코드 내 위치:

val navController = rememberNavController()

코드 내 역할:

  • rememberNavController()를 통해 생성되어 컴포저블의 생명주기 동안 상태를 유지합니다.
  • HomeScreen의 콜백 함수 내에서 실제로 화면을 이동시키는 명령을 수행합니다: navController.navigate(DetailRoute(itemId = itemId))

핵심요소2. Route (경로/목적지 식별자)

Route 는 네비게이션이 도달할 특정 화면(Destination) 을 유일하게 식별하는 경로입니다. 전통적으로는 문자열을 사용했지만, 제공된 코드에서는 제가 선호하는 타입 안전성을 위해 @Serializable 클래스를 사용합니다.

역할: 특정 목적지를 가리키는 주소의 역할을 합니다. 인자가 필요할 경우, 해당 인자를 Route 객체의 속성으로 포함합니다.

코드 내 위치:

@Serializable
object HomeRoute

@Serializable
data class DetailRoute(val itemId: Int)

코드 내 역할:

  • HomeRoute는 인자가 필요 없는 홈 화면의 주소를 나타냅니다.
  • DetailRoute(val itemId: Int)itemId라는 인자를 포함하는 상세 화면의 주소를 나타냅니다. 네비게이션 시 이 객체를 전달하고 (navController.navigate(DetailRoute(...))), 목적지에서 다시 추출하여 사용합니다

핵심요소3. NavHost (네비게이션 호스트)

NavHost 는 네비게이션이 일어나는 영역을 정의하며, 현재의 Route에 해당하는 실제 UI(Composable) 를 표시하는 컨테이너입니다.

역할: 네비게이션 그래프(NavGraph)와 NavController 를 연결하고, 현재 상태에 따라 적절한 NavDestination의 컴포저블을 렌더링합니다.

코드 내 위치:

NavHost(
    navController = navController, 
    startDestination = HomeRoute // 시작 지점
) {
    // ... 목적지 등록 ...
}

코드 내 역할:

  • navController와 연결되어 네비게이션 이벤트를 받습니다.
  • startDestination으로 앱이 시작될 때 처음 보여줄 화면을 지정합니다.
  • 빌더(NavGraphBuilder.() -> Unit)의 composable<T> 함수를 통해 목적지들을 등록합니다. (navController.createGraph(...) 통해 그래프 객체를 만들어서 전달주는 방법도 가능합니다.)

핵심요소4. NavDestination (네비게이션 목적지)

NavDestination 은 네비게이션을 통해 도달할 수 있는 하나의 독립된 화면 단위를 의미하며, 일반적으로 특정 Composable 을 감싸고 있습니다.

역할: 네비게이션 그래프 내의 노드(Node)입니다. composable<T> 블록 하나가 하나의 NavDestination을 생성합니다.

코드 내 위치:

composable<HomeRoute> { 
    HomeScreen(...) 
} 
// 그리고
composable<DetailRoute> { 
    DetailScreen(...) 
}

코드 내 역할:

  • composable<T> 블록은 HomeRouteDetailRoute라는 Route에 매핑되는 개별적인 목적지 를 정의합니다.
  • 이 목적지 내부에 HomeScreenDetailScreen 컴포저블이 위치합니다.

핵심요소5. NavGraph (네비게이션 그래프)

NavGraph 는 앱 내의 모든 NavDestination들을 모아 연결해 놓은 집합체로, 네비게이션의 구조를 정의합니다.

역할:
앱의 모든 화면(Destination)과 그 화면들 간의 이동 가능한 경로(Action)를 정의하는 지도 또는 청사진 입니다. NavHost 내의 블록 자체가 하나의 그래프를 구성합니다.

코드 내 위치:

NavHost(...) {
    // 이 블록 전체가 NavGraph를 정의합니다.
    composable<HomeRoute> { ... }
    composable<DetailRoute> { ... }
}

코드 내 역할:

  • NavHost의 블록({}) 내에 등록된 모든 composable 목적지들을 포함하여 "이 앱에서는 HomeRoute와 DetailRoute로 이동할 수 있다" 는 전체 구조를 NavController에게 제공합니다.
  • startDestination = HomeRoute는 이 그래프의 시작점을 명시합니다.

마치며

기본적인 Compose Navigation2 라이브러리의 사용방법을 간단하게 알아봤습니다.
Navigation3가 나온 시점에서 Navigation2 를 자세히 알아보기 보다는 기본적인 구성요소와 사용법만을 알아보고 다음 포스트에서 Navigation3 의 소개와 Navigation2와 비교했을 때의 장점을 알아보도록 하겠습니다.


Logo picture

Written by Song YunGi Android, iOS Developer.

GitHub 프로필