대상으로 이동

대상으로 이동하는 것은 NavController 객체를 사용하여 실행되며 이 객체는 NavHost 내에서 앱 탐색을 관리합니다. 각 NavHost에는 그에 상응하는 자체 NavController가 있습니다. NavController를 사용하면 몇 가지 방식으로 대상으로 이동할 수 있습니다. 이 방식에 관해서는 아래 섹션에서 자세히 설명합니다.

프래그먼트, 활동 또는 뷰의 NavController를 가져오려면 다음 메서드 중 하나를 사용합니다.

Kotlin:

자바:

NavController를 가져온 후 navigate()의 오버로드 중 하나를 호출하여 대상 사이를 이동할 수 있습니다. 다음 섹션에서 설명하는 것처럼 각 오버로드는 다양한 탐색 시나리오를 지원합니다.

유형에 안전한 탐색을 위한 Safe Arg 사용

대상 간 이동을 위해 Safe Args Gradle 플러그인을 사용하는 것이 좋습니다. 이 플러그인은 대상 간에 유형 안전 탐색을 할 수 있도록 하는 간단한 객체 및 빌더 클래스를 생성합니다. Safe Args는 탐색과 대상 간 데이터 전달 모두에 좋습니다.

프로젝트에 Safe Args를 추가하려면 최상위 build.gradle 파일에 다음의 classpath를 포함합니다.

Groovy

buildscript {
    repositories {
        google()
    }
    dependencies {
        def nav_version = "2.3.5"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

Kotlin

buildscript {
    repositories {
        google()
    }
    dependencies {
        val nav_version = "2.3.5"
        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 예

한 예로 SpecifyAmountFragmentConfirmationFragment 두 대상을 연결하는 단일 작업을 가진 탐색 그래프를 가정해 보겠습니다. 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를 사용하여 이동할 때 백 스택은 재설정되지 않습니다. 이 동작은 다른 딥 링크 탐색과 달리 이동 중 백 스택이 교체됩니다. popUpTopopUpToInclusive는 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:popUpTonavigate() 호출의 일부로 백 스택에서 몇 개의 대상을 팝하도록 탐색 라이브러리에 알려줍니다. 속성값은 스택에 남아 있어야 하는 가장 최근 대상의 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:popUpToapp: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 인스턴스 두 개를 포함하게 됩니다.