탐색은 사용자가 앱을 이동하는 방식을 나타냅니다. 사용자는 일반적으로 UI 요소를 탭하거나 클릭하여 상호작용하며 앱은 새 콘텐츠를 표시하여 응답합니다. 사용자가 이전 콘텐츠로 돌아가려면 뒤로 동작을 사용하거나 뒤로 버튼을 탭합니다.
탐색 상태 모델링
이 동작을 모델링하는 편리한 방법은 콘텐츠 스택을 사용하는 것입니다. 사용자가 새 콘텐츠로 이동하면 스택의 맨 위에 푸시됩니다. 사용자가 해당 콘텐츠에서 뒤로 이동하면 스택에서 콘텐츠가 팝되고 이전 콘텐츠가 표시됩니다. 탐색 용어로 이 스택은 사용자가 되돌아갈 수 있는 콘텐츠를 나타내므로 일반적으로 뒤로 스택이라고 합니다.
그림 1. 사용자 탐색 이벤트에 따라 뒤로 스택이 어떻게 변경되는지 보여주는 다이어그램
백 스택 만들기
탐색 3에서는 뒤로 스택에 실제로 콘텐츠가 포함되지 않습니다. 대신 키라고 하는 콘텐츠 참조가 포함됩니다. 키는 어떤 유형이든 될 수 있지만 일반적으로 직렬화 가능한 간단한 데이터 클래스입니다. 콘텐츠 대신 참조를 사용하면 다음과 같은 이점이 있습니다.
키를 백 스택에 푸시하여 간단하게 탐색할 수 있습니다.
키가 직렬화 가능한 한 백 스택을 영구 저장소에 저장할 수 있으므로 구성 변경 및 프로세스 종료 후에도 유지할 수 있습니다. 이는 사용자가 앱을 나갔다가 나중에 다시 돌아와서 중단한 지점부터 동일한 콘텐츠가 표시되기를 기대하기 때문에 중요합니다. 자세한 내용은 뒤로 스택 저장을 참고하세요.
Navigation 3 API의 핵심 개념은 뒤로 스택을 소유한다는 것입니다. 라이브러리는 다음을 실행합니다.
백 스택이 스냅샷 상태 백업 List<T>이어야 합니다. 여기서 T은 백 스택 keys의 유형입니다. Any를 사용하거나 더 강력한 유형의 자체 키를 제공할 수 있습니다. '푸시' 또는 '팝'이라는 용어가 표시되면 기본 구현은 목록 끝에 항목을 추가하거나 삭제하는 것입니다.
다음 예에서는 키와 백 스택을 만들고 사용자 탐색 이벤트에 응답하여 백 스택을 수정하는 방법을 보여줍니다.
// Define keys that will identify contentdataobjectProductListdataclassProductDetail(valid:String)@ComposablefunMyApp(){// Create a back stack, specifying the key the app should start withvalbackStack=remember{mutableStateListOf<Any>(ProductList)}// Supply your back stack to a NavDisplay so it can reflect changes in the UI// ...more on this below...// Push a key onto the back stack (navigate forward), the navigation library will reflect the change in statebackStack.add(ProductDetail(id="ABC"))// Pop a key off the back stack (navigate back), the navigation library will reflect the change in statebackStack.removeLastOrNull()}
콘텐츠는 컴포저블 함수가 포함된 클래스인 NavEntry를 사용하여 Navigation 3에서 모델링됩니다. 대상을 나타냅니다. 즉, 사용자가 이어서 이동하고 이전할 수 있는 단일 콘텐츠입니다.
NavEntry에는 콘텐츠에 관한 정보인 메타데이터도 포함될 수 있습니다. 이 메타데이터는 NavDisplay와 같은 컨테이너 객체에서 읽을 수 있으므로 NavEntry의 콘텐츠를 표시하는 방법을 결정하는 데 도움이 됩니다. 예를 들어 메타데이터를 사용하여 특정 NavEntry의 기본 애니메이션을 재정의할 수 있습니다. NavEntry metadata는 String 키를 Any 값에 매핑하여 다양한 데이터 저장소를 제공합니다.
key를 NavEntry로 변환하려면 항목 제공자를 만듭니다. key를 수락하고 해당 key의 NavEntry를 반환하는 함수입니다. 일반적으로 NavDisplay를 만들 때 람다 매개변수로 정의됩니다.
엔트리 제공자를 만드는 방법에는 두 가지가 있습니다. 람다 함수를 직접 만들거나 entryProvider DSL을 사용하는 것입니다.
항목 제공자 함수 직접 만들기
일반적으로 when 문을 사용하여 항목 제공자 함수를 만들고 각 키에 대한 브랜치를 사용합니다.
entryProvider DSL은 각 키 유형에 대해 테스트할 필요가 없으므로 람다 함수를 단순화하고 각 키 유형에 대해 NavEntry를 구성할 수 있습니다.
이를 위해 entryProvider 빌더 함수를 사용합니다. 키를 찾을 수 없는 경우의 기본 대체 동작 (오류 발생)도 포함되어 있습니다.
entry는 metadata 매개변수를 사용하여 NavEntry.metadata를 설정합니다.
백 스택 표시
백 스택은 앱의 탐색 상태를 나타냅니다. 백 스택이 변경될 때마다 앱 UI는 새 백 스택 상태를 반영해야 합니다. Navigation 3에서 NavDisplay는 백 스택을 관찰하고 그에 따라 UI를 업데이트합니다. 다음 매개변수를 사용하여 생성합니다.
백 스택 - SnapshotStateList<T> 유형이어야 하며 여기서 T는 백 스택 키의 유형입니다. 관찰 가능한 List이므로 변경될 때 NavDisplay의 리컴포지션을 트리거합니다.
백 스택의 키를 NavEntry로 변환하는 entryProvider입니다.
원하는 경우 onBack 매개변수에 람다를 제공합니다. 사용자가 뒤로 이벤트를 트리거할 때 호출됩니다.
다음 예는 NavDisplay를 만드는 방법을 보여줍니다.
dataobjectHomedataclassProduct(valid:String)@ComposablefunNavExample(){valbackStack=remember{mutableStateListOf<Any>(Home)}NavDisplay(backStack=backStack,onBack={backStack.removeLastOrNull()},entryProvider={key->
when(key){isHome->NavEntry(key){ContentGreen("Welcome to Nav3"){Button(onClick={backStack.add(Product("123"))}){Text("Click to navigate")}}}isProduct->NavEntry(key){ContentBlue("Product ${key.id} ")}else->NavEntry(Unit){Text("Unknown route")}}})}
기본적으로 NavDisplay는 단일 창 레이아웃에서 백 스택의 최상위 NavEntry를 표시합니다. 다음 녹화 파일은 이 앱이 실행되는 모습을 보여줍니다.
그림 2. 두 대상이 있는 NavDisplay 기본 동작
종합적으로 살펴보기
다음 다이어그램은 탐색 3의 여러 객체 간에 데이터가 흐르는 방식을 보여줍니다.
그림 3. 탐색 3에서 데이터가 다양한 객체를 통해 흐르는 방식을 보여주는 다이어그램
탐색 이벤트가 변경을 시작합니다. 키는 사용자 상호작용에 응답하여 백 스택에 추가되거나 삭제됩니다.
백 스택 상태 변경이 콘텐츠 검색을 트리거합니다. NavDisplay(백 스택을 렌더링하는 컴포저블)는 백 스택을 관찰합니다. 기본 구성에서는 단일 창 레이아웃에 최상위 백 스택 항목을 표시합니다. 백 스택의 최상위 키가 변경되면 NavDisplay는 이 키를 사용하여 항목 제공업체에 해당 콘텐츠를 요청합니다.
항목 제공업체가 콘텐츠를 제공합니다. 항목 제공업체는 키를 NavEntry로 확인하는 함수입니다. 항목 제공업체는 NavDisplay에서 키를 수신하면 키와 콘텐츠가 모두 포함된 연결된 NavEntry를 제공합니다.
콘텐츠가 표시됩니다. NavDisplay는 NavEntry를 수신하고 콘텐츠를 표시합니다.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-07-27(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-07-27(UTC)"],[],[],null,["# Understand and implement the basics\n\nNavigation describes the way users move around your app. Users interact with UI\nelements, usually by tapping or clicking on them, and the app responds by\ndisplaying new content. If the user wants to go back to the previous content,\nthey use the back gesture or tap the back button.\n\nModeling navigation state\n-------------------------\n\nA convenient way of modeling this behavior is with a stack of content. As the\nuser navigates *forward* to new content, it is pushed on top of the stack. When\nthey go *back* from that content, it is popped off the stack and the previous\ncontent is displayed. In navigation terms, this stack is usually referred to as\nthe **back stack** because it represents the content that the user *can go back\nto*.\n**Figure 1.** Diagram showing how the back stack changes with user navigation events.\n\nCreate a back stack\n-------------------\n\nIn Navigation 3, the back stack does not actually contain content. Instead, it\ncontains *references to content* , known as **keys**. Keys can be any type but\nare usually simple, serializable data classes. Using references rather than\ncontent has the following benefits:\n\n- It is simple to navigate by pushing keys onto the back stack.\n- As long as the keys are serializable, the back stack can be saved to persistent storage, allowing it to survive configuration changes and process death. This is important because users expect to leave your app, come back to it later, and pick up where they left off with the same content being displayed. See [Save your back stack](/guide/navigation/navigation-3/save-state#save-back) for more information.\n\nA key concept in the Navigation 3 API is that you own the back stack. The\nlibrary:\n\n- Expects that your back stack will be a snapshot-state backed `List\u003cT\u003e`, where `T` is the type of your back stack `keys`. You can use `Any` or you can provide your own, more strongly-typed keys. When you see the terms \"push\" or \"pop\", the underlying implementation is to add or remove items from the end of a list.\n- Observes your back stack and reflects its state in the UI using a [`NavDisplay`](/reference/kotlin/androidx/navigation3/ui/package-summary#NavDisplay(kotlin.collections.List,androidx.compose.ui.Modifier,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.collections.List,androidx.navigation3.ui.SceneStrategy,androidx.compose.animation.SizeTransform,kotlin.Function1,kotlin.Function1,kotlin.Function1,kotlin.Function1)).\n\nThe following example shows how to create keys and a back stack, and modify the\nback stack in response to user navigation events:\n\n\n```kotlin\n// Define keys that will identify content\ndata object ProductList\ndata class ProductDetail(val id: String)\n\n@Composable\nfun MyApp() {\n\n // Create a back stack, specifying the key the app should start with\n val backStack = remember { mutableStateListOf\u003cAny\u003e(ProductList) }\n\n // Supply your back stack to a NavDisplay so it can reflect changes in the UI\n // ...more on this below...\n\n // Push a key onto the back stack (navigate forward), the navigation library will reflect the change in state\n backStack.add(ProductDetail(id = \"ABC\"))\n\n // Pop a key off the back stack (navigate back), the navigation library will reflect the change in state\n backStack.removeLastOrNull()\n}https://github.com/android/snippets/blob/26d364466ee1c03d658ba2f0905f7cc1a97afefa/compose/snippets/src/main/java/com/example/compose/snippets/navigation3/basic/BasicSnippets.kt#L33-L51\n```\n\n\u003cbr /\u003e\n\nResolve keys to content\n-----------------------\n\nContent is modeled in Navigation 3 using [`NavEntry`](/reference/kotlin/androidx/navigation3/runtime/NavEntry), which is a class\ncontaining a composable function. It represents a *destination* - a single piece\nof content that the user can navigate *forward to* and *back from*.\n\nA `NavEntry` can also contain metadata - information about the content. This\nmetadata can be read by container objects, like `NavDisplay`, to help them\ndecide how to display the `NavEntry`'s content. For example, metadata can be\nused to override the default animations for a specific `NavEntry`. NavEntry\n`metadata` is a map of `String` keys to `Any` values, providing versatile data\nstorage.\n\nTo convert a `key` to a `NavEntry`, create an Entry Provider. This is a\nfunction that accepts a `key` and returns a `NavEntry` for that `key`. It is\nusually defined as a lambda parameter when creating a `NavDisplay`.\n\nThere are two ways to create an Entry Provider, either by creating a lambda\nfunction directly, or by using the [`entryProvider`](/reference/kotlin/androidx/navigation3/runtime/package-summary#entryProvider(kotlin.Function1,kotlin.Function1)) DSL.\n\n### Create an Entry Provider function directly\n\nYou typically create an Entry Provider function using a `when` statement, with\na branch for each of your keys.\n\n\n```kotlin\nentryProvider = { key -\u003e\n when (key) {\n is ProductList -\u003e NavEntry(key) { Text(\"Product List\") }\n is ProductDetail -\u003e NavEntry(\n key,\n metadata = mapOf(\"extraDataKey\" to \"extraDataValue\")\n ) { Text(\"Product ${key.id} \") }\n\n else -\u003e {\n NavEntry(Unit) { Text(text = \"Invalid Key: $it\") }\n }\n }\n}https://github.com/android/snippets/blob/26d364466ee1c03d658ba2f0905f7cc1a97afefa/compose/snippets/src/main/java/com/example/compose/snippets/navigation3/basic/BasicSnippets.kt#L60-L72\n```\n\n\u003cbr /\u003e\n\n### Use the `entryProvider` DSL\n\nThe `entryProvider` DSL can simplify your lambda function by avoiding the need\nto test against each of your key types, and construct a `NavEntry` for each one.\nUse the `entryProvider` builder function for this. It also includes default\nfallback behavior (throwing an error) if the key isn't found.\n\n\n```kotlin\nentryProvider = entryProvider {\n entry\u003cProductList\u003e { Text(\"Product List\") }\n entry\u003cProductDetail\u003e(\n metadata = mapOf(\"extraDataKey\" to \"extraDataValue\")\n ) { key -\u003e Text(\"Product ${key.id} \") }\n}https://github.com/android/snippets/blob/26d364466ee1c03d658ba2f0905f7cc1a97afefa/compose/snippets/src/main/java/com/example/compose/snippets/navigation3/basic/BasicSnippets.kt#L83-L88\n```\n\n\u003cbr /\u003e\n\nNote the following from the snippet:\n\n- `entry` is used to define a `NavEntry` with the given type and composable content\n- `entry` accepts a `metadata` parameter to set `NavEntry.metadata`\n\nDisplay the back stack\n----------------------\n\nThe back stack represents your app's navigation state. Whenever the back stack\nchanges, the app UI should reflect the new back stack state. In Navigation 3, a\n`NavDisplay` observes your back stack and updates its UI accordingly. Construct\nit with following parameters:\n\n- Your back stack - this should be of type `SnapshotStateList\u003cT\u003e`, where `T` is the type of your back stack keys. It is an observable `List` so that it triggers recomposition of `NavDisplay` when it changes.\n- An `entryProvider` to convert the keys in your back stack to `NavEntry`s.\n- Optionally, supply a lambda to the `onBack` parameter. This is called when the user triggers a back event.\n\nThe following example shows how to create a `NavDisplay`.\n\n\n```kotlin\ndata object Home\ndata class Product(val id: String)\n\n@Composable\nfun NavExample() {\n\n val backStack = remember { mutableStateListOf\u003cAny\u003e(Home) }\n\n NavDisplay(\n backStack = backStack,\n onBack = { backStack.removeLastOrNull() },\n entryProvider = { key -\u003e\n when (key) {\n is Home -\u003e NavEntry(key) {\n ContentGreen(\"Welcome to Nav3\") {\n Button(onClick = {\n backStack.add(Product(\"123\"))\n }) {\n Text(\"Click to navigate\")\n }\n }\n }\n\n is Product -\u003e NavEntry(key) {\n ContentBlue(\"Product ${key.id} \")\n }\n\n else -\u003e NavEntry(Unit) { Text(\"Unknown route\") }\n }\n }\n )\n}https://github.com/android/snippets/blob/26d364466ee1c03d658ba2f0905f7cc1a97afefa/compose/snippets/src/main/java/com/example/compose/snippets/navigation3/basic/BasicSnippets.kt#L94-L125\n```\n\n\u003cbr /\u003e\n\nBy default, the `NavDisplay` shows the topmost `NavEntry` on the back stack in a\nsingle pane layout. The following recording shows this app running:\n**Figure 2.** `NavDisplay` default behavior with two destinations.\n\nPutting it all together\n-----------------------\n\nThe following diagram shows how data flows between the various objects in\nNavigation 3:\n**Figure 3.** Diagram showing how data flows through various objects in Navigation 3.\n\n1. **Navigation events initiate changes**. Keys are added or removed from the\n back stack in response to user interactions.\n\n2. **Change in back stack state triggers content retrieval** . The `NavDisplay`\n (a composable that renders a back stack) observes the back stack. In its\n default configuration, it displays the topmost back stack entry in a single\n pane layout. When the top key on the back stack changes, the `NavDisplay` uses\n this key to request the corresponding content from the entry provider.\n\n3. **Entry provider supplies content** . The entry provider is a function that\n resolves a key to a `NavEntry`. Upon receiving a key from the `NavDisplay`,\n the entry provider provides the associated `NavEntry`, which contains both the\n key and the content.\n\n4. **Content is displayed** . The `NavDisplay` receives the `NavEntry` and\n displays the content."]]