대상으로 이동하는 것은 NavController
객체를 사용하여 실행되며 이 객체는 NavHost
내에서 앱 탐색을 관리합니다. 각 NavHost
에는 그에 상응하는 자체 NavController
가 있습니다. NavController
를 사용하면 몇 가지 방식으로 대상으로 이동할 수 있습니다. 이 방식에 관해서는 아래 섹션에서 자세히 설명합니다.
프래그먼트, 활동 또는 뷰의 NavController
를 가져오려면 다음 메서드 중 하나를 사용합니다.
Kotlin:
자바:
NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
NavController
를 가져온 후 navigate()
의 오버로드 중 하나를 호출하여 대상 사이를 이동할 수 있습니다. 다음 섹션에서 설명하는 것처럼 각 오버로드는 다양한 탐색 시나리오를 지원합니다.
유형에 안전한 탐색을 위한 Safe Arg 사용
대상 간 이동을 위해 Safe Args Gradle 플러그인을 사용하는 것이 좋습니다. 이 플러그인은 대상 간에 유형 안전 탐색을 할 수 있도록 하는 간단한 객체 및 빌더 클래스를 생성합니다. Safe Args는 탐색과 대상 간 데이터 전달 모두에 좋습니다.
프로젝트에 Safe Args를 추가하려면 최상위 build.gradle
파일에 다음의 classpath
를 포함합니다.
Groovy
buildscript { repositories { google() } dependencies { def nav_version = "2.5.3" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" } }
Kotlin
buildscript { repositories { google() } dependencies { val nav_version = "2.5.3" classpath("androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version") } }
또한 사용 가능한 두 가지 플러그인 중 하나를 적용해야 합니다.
자바 모듈 또는 자바와 Kotlin 혼합 모듈에 적합한 자바 언어 코드를 생성하려면 앱 또는 모듈의 build.gradle
파일에 다음 행을 추가합니다.
Groovy
plugins { id 'androidx.navigation.safeargs' }
Kotlin
plugins { id("androidx.navigation.safeargs") }
또는 Kotlin 전용 모듈에 적합한 Kotlin 코드를 생성하려면 다음을 추가하세요.
Groovy
plugins { id 'androidx.navigation.safeargs.kotlin' }
Kotlin
plugins { id("androidx.navigation.safeargs.kotlin") }
AndroidX로 이전에 따라 gradle.properties
파일에 android.useAndroidX=true
가 있어야 합니다.
Safe Args를 사용 설정하면 생성된 코드에 정의한 작업의 클래스 및 메서드와 각 발신 및 수신 대상에 상응하는 클래스가 포함됩니다.
Safe Args는 작업이 발생하는 각 대상의 클래스를 생성합니다. 생성된 클래스 이름은 발신 대상 클래스 이름에 'Directions'를 붙입니다. 예를 들어, 발신 대상 이름이 SpecifyAmountFragment
라면 생성된 클래스 이름은 SpecifyAmountFragmentDirections
가 됩니다.
생성된 클래스에는 발신 대상에서 정의한 각 작업의 정적 메서드가 포함됩니다. 이 메서드는 정의된 모든 작업 매개변수를 인수로 사용하고 navigate()
에 직접 전달할 수 있는 NavDirections
객체를 반환합니다.
Safe Args 예
한 예로 SpecifyAmountFragment
와 ConfirmationFragment
두 대상을 연결하는 단일 작업을 가진 탐색 그래프를 가정해 보겠습니다.
ConfirmationFragment
는 작업의 일부로 제공되는 단일 float
매개변수를 사용합니다.
Safe Args는 단일 메서드(actionSpecifyAmountFragmentToConfirmationFragment()
)를 가진 SpecifyAmountFragmentDirections
클래스와 내부 클래스(ActionSpecifyAmountFragmentToConfirmationFragment
)를 생성합니다. 내부 클래스는 NavDirections
에서 파생된 클래스이며 연결된 작업 ID와 float
매개변수를 저장합니다. 그런 다음 아래 예와 같이 반환된 NavDirections
객체를 직접 navigate()
에 전달하면 됩니다.
Kotlin
override fun onClick(v: View) { val amount: Float = ... val action = SpecifyAmountFragmentDirections .actionSpecifyAmountFragmentToConfirmationFragment(amount) v.findNavController().navigate(action) }
자바
@Override public void onClick(View view) { float amount = ...; action = SpecifyAmountFragmentDirections .actionSpecifyAmountFragmentToConfirmationFragment(amount); Navigation.findNavController(view).navigate(action); }
Safe Args를 사용하여 대상 간에 데이터를 전달하는 방법에 관한 자세한 내용은 Safe Args를 사용하여 유형 안전성을 갖춘 데이터 전달을 참고하세요.
ID를 사용한 이동
navigate(int)
는 작업 또는 대상의 리소스 ID를 사용합니다. 다음 코드 스니펫은 ViewTransactionsFragment
로 이동하는 방법을 보여줍니다.
Kotlin
viewTransactionsButton.setOnClickListener { view -> view.findNavController().navigate(R.id.viewTransactionsAction) }
자바
viewTransactionsButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Navigation.findNavController(view).navigate(R.id.viewTransactionsAction); } });
버튼의 경우, 아래 예와 같이 Navigation
클래스의 createNavigateOnClickListener()
편의 메서드를 사용하여 대상으로 이동할 수도 있습니다.
Kotlin
button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null))
자바
button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null));
상단의 앱 바 및 하단 탐색 같은 다른 공통 UI 구성요소를 처리하려면 NavigationUI로 UI 구성요소 업데이트를 참고하세요.
작업에 탐색 옵션 제공
탐색 그래프에 작업을 정의하면 탐색은 상응하는 NavAction
클래스를 생성하며 그 클래스에는 다음을 포함하여 작업을 위해 정의된 구성이 포함됩니다.
- 대상: 타겟 대상의 리소스 ID입니다.
- 기본 인수: 타겟 대상의 기본값을 포함하는
android.os.Bundle
입니다(제공되는 경우만 사용함). - 탐색 옵션:
NavOptions
로 표시되는 탐색 옵션입니다. 이 클래스에는 타겟 대상으로 또는 타겟 대상에서 다시 전환될 때 필요한 모든 특별 구성(예: 애니메이션 리소스 구성, 팝업 동작, 단일 최상위 모드에서 대상이 시작되어야 하는지 여부 등)이 포함됩니다.
한 곳에서 다른 곳으로 이동하는 작업에 따라 두 화면을 구성하는 그래프 예를 보겠습니다.
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/a">
<fragment android:id="@+id/a"
android:name="com.example.myapplication.FragmentA"
android:label="a"
tools:layout="@layout/a">
<action android:id="@+id/action_a_to_b"
app:destination="@id/b"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim"/>
</fragment>
<fragment android:id="@+id/b"
android:name="com.example.myapplication.FragmentB"
android:label="b"
tools:layout="@layout/b">
<action android:id="@+id/action_b_to_a"
app:destination="@id/a"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim"
app:popUpTo="@+id/a"
app:popUpToInclusive="true"/>
</fragment>
</navigation>
탐색 그래프가 확장되면 이러한 작업은 파싱되고 그래프에 정의된 구성을 사용하여 작업에 상응하는 NavAction
객체가 생성됩니다. 예를 들어, action_b_to_a
는 대상 b
에서 대상 a
로의 이동으로 정의됩니다. 작업에는 애니메이션 및 백 스택에서 모든 대상을 삭제하는 popTo
동작이 포함됩니다. 이러한 모든 설정은 NavOptions
로 캡처되고 NavAction
에 연결됩니다.
이 NavAction
을 팔로우하려면 다음 예와 같이 NavController.navigate()
를 사용하여 작업의 ID를 전달합니다.
Kotlin
findNavController().navigate(R.id.action_b_to_a)
자바
NavigationHostFragment.findNavController(this).navigate(R.id.action_b_to_a);
DeepLinkRequest를 사용한 탐색
다음 예와 같이 navigate(NavDeepLinkRequest)
를 사용하여 직접 암시적 딥 링크 대상으로 이동할 수 있습니다.
Kotlin
val request = NavDeepLinkRequest.Builder .fromUri("android-app://androidx.navigation.app/profile".toUri()) .build() findNavController().navigate(request)
자바
NavDeepLinkRequest request = NavDeepLinkRequest.Builder .fromUri(Uri.parse("android-app://androidx.navigation.app/profile")) .build() NavHostFragment.findNavController(this).navigate(request)
Uri
외에 NavDeepLinkRequest
도 작업 및 MIME 유형이 있는 딥 링크를 지원합니다. 작업을 요청에 추가하려면 fromAction()
또는 setAction()
을 사용합니다.
MIME 유형을 요청에 추가하려면 fromMimeType()
또는 setMimeType()
을 사용합니다.
NavDeepLinkRequest
가 암시적 딥 링크 대상과 올바르게 일치하려면 URI, 작업, MIME 유형이 모두 대상의 NavDeepLink
와 일치해야 합니다. URI는 패턴과 일치해야 하고 작업은 정확하게 일치해야 하며 MIME 유형은 관련되어야 합니다(예: 'image/jpg'는 'image/*'와 일치).
작업 또는 대상 ID를 사용하는 탐색과 달리 대상이 표시되는 여부와 상관없이 그래프의 모든 딥 링크로 이동할 수 있습니다. 현재 그래프에서 대상으로 이동하거나 완전히 다른 그래프의 대상으로 이동할 수 있습니다.
NavDeepLinkRequest
를 사용하여 이동할 때 백 스택은 재설정되지 않습니다. 이 동작은 다른 딥 링크 탐색과 달리 이동 중 백 스택이 교체됩니다. popUpTo
및 popUpToInclusive
는 ID를 사용하여 이동한 것처럼 백 스택에서 여전히 대상을 삭제합니다.
탐색 및 백 스택
Android는 방문한 대상을 포함하는 백 스택을 유지합니다. 앱의 첫 번째 대상은 앱을 열 때 스택에 배치됩니다. navigate()
메서드는 호출될 때마다 또 다른 대상을 스택의 맨 위에 놓습니다. 위로 또는 뒤로를 탭하면 NavController.navigateUp()
과 NavController.popBackStack()
메서드가 각각 호출되어 스택 최상단의 대상을 삭제(또는 팝)합니다.
NavController.popBackStack()
은 백 스택에서 팝한 후 다른 대상이 최상단에 성공적으로 다시 배치되었는지를 나타내는 부울을 반환합니다. 이 메서드가 false
를 반환하는 가장 일반적인 경우는 그래프의 시작 대상을 수동으로 팝할 때입니다.
이 메서드가 false
를 반환하면 NavController.getCurrentDestination()
은 null
을 반환합니다. 아래 예와 같이 새 대상으로 이동하거나 활동의 finish()
를 호출하여 팝을 처리해야 합니다.
Kotlin
... if (!navController.popBackStack()) { // Call finish() on your Activity finish() }
자바
... if (!navController.popBackStack()) { // Call finish() on your Activity finish(); }
popUpTo 및 popUpToInclusive
작업을 사용하여 이동할 때 백 스택에서 추가 대상을 팝하도록 선택할 수 있습니다. 예를 들어, 앱에 초기 로그인 흐름이 있다면 사용자가 로그인했을 때 사용자가 뒤로 버튼을 눌러도 로그인 흐름으로 돌아가지 않도록 로그인과 관련된 모든 대상을 백 스택에서 팝해야 합니다.
한 대상에서 다른 대상으로 이동할 때 대상을 팝하려면 app:popUpTo
속성을 연결된 <action>
요소에 추가합니다. app:popUpTo
는 navigate()
호출의 일부로 백 스택에서 몇 개의 대상을 팝하도록 탐색 라이브러리에 알려줍니다. 속성값은 스택에 남아 있어야 하는 가장 최근 대상의 ID입니다.
또한, app:popUpToInclusive="true"
를 포함하여 app:popUpTo
에 지정된 대상이 백 스택에서 삭제될 수도 있다는 것을 나타낼 수도 있습니다.
popUpTo 예: 순환 로직
앱에 A, B, C 세 개의 대상과 A에서 B로, B에서 C로, C에서 A로 연결되는 작업이 있다고 가정해 보겠습니다. 이에 상응하는 탐색 그래프는 그림 1과 같습니다.
그림 1. A, B, C 세 개의 대상이 있는 순환 탐색 그래프
각 탐색 작업에서 대상이 백 스택에 추가됩니다. 이 흐름을 통해 반복적으로 이동한다면 백 스택에는 각 대상의 여러 세트(A, B, C, A, B, C, A 등)가 포함됩니다.
이 반복을 피하려면 다음 예와 같이 대상 C에서 대상 A로 이동하는 작업에 app:popUpTo
와 app:popUpToInclusive
를 지정하면 됩니다.
<fragment android:id="@+id/c" android:name="com.example.myapplication.C" android:label="fragment_c" tools:layout="@layout/fragment_c"> <action android:id="@+id/action_c_to_a" app:destination="@id/a" app:popUpTo="@+id/a" app:popUpToInclusive="true"/> </fragment>
대상 C에 도달한 후 백 스택은 각 대상(A, B, C)의 한 인스턴스를 포함합니다. 대상 A로 다시 이동하면 A도 popUpTo
하며 이는 이동하는 동안 B와 C를 스택에서 삭제하는 것을 의미합니다. app:popUpToInclusive="true"
인 경우 스택에서 첫 번째 A도 팝하여 효과적으로 스택을 비웁니다. app:popUpToInclusive
를 사용하지 않는다면 백 스택은 대상 A 인스턴스 두 개를 포함하게 됩니다.