대상 간 데이터 전달

탐색을 사용하면 대상 인수를 정의하여 탐색 작업에 데이터를 연결할 수 있습니다. 예를 들어 사용자 프로필 대상은 사용자 ID 인수를 사용하여 표시할 사용자를 결정할 수 있습니다.

일반적으로 대상 간에 최소한의 데이터만 전달하는 것이 좋습니다. 예를 들어 객체 자체를 전달하지 않고 키를 전달하여 객체를 검색해야 하는데 이는 모든 저장된 상태의 총 공간이 Android에서 제한되기 때문입니다. 많은 양의 데이터를 전달해야 한다면 ViewModel 개요에 설명된 대로 ViewModel를 사용합니다.

대상 인수 정의

대상 간에 데이터를 전달하려면 먼저 다음 단계에 따라 인수를 받는 대상에 추가하여 인수를 정의합니다.

  1. Navigation Editor에서 인수를 받는 대상을 클릭합니다.
  2. Attributes 패널에서 Add(+)를 클릭합니다.
  3. 표시되는 Add Argument Link 창에서 인수 이름과 인수 유형, 인수의 null 허용 여부 그리고 필요하다면 기본값을 입력합니다.
  4. Add를 클릭합니다. 이제 Attributes 패널의 Arguments 목록에 인수가 표시됩니다.
  5. 그런 다음 도착 페이지로 이동하는 해당 작업을 클릭합니다. Attributes 패널에서 이제는 Argument Default Values 섹션에 새롭게 추가된 인수가 표시됩니다.
  6. 또한 인수가 XML에 추가된 것을 알 수 있습니다. Text 탭을 클릭하여 XML 뷰로 전환하면 인수가 인수를 받는 대상에 추가된 것을 확인할 수 있습니다. 아래 예를 참고하세요.

     <fragment android:id="@+id/myFragment" >
         <argument
             android:name="myArg"
             app:argType="integer"
             android:defaultValue="0" />
     </fragment>
    

지원되는 인수 유형

탐색 라이브러리는 다음 인수 유형을 지원합니다.

유형 app:argType 문법 기본값 지원 경로에서 처리됨 Null 허용됨
정수 app:argType="integer" 아니요
Float app:argType="float" 아니요
Long app:argType="long" 예 - 기본값은 항상 'L' 접미사로 끝나야 합니다(예: '123L'). 아니요
부울 app:argType="boolean" 예 - 'true' 또는 'false' 아니요
문자열 app:argType="string"
리소스 참조 app:argType="reference" 예 - 기본값은 '@resourceType/resourceName'(예: '@style/myCustomStyle') 형식이나 '0'이어야 합니다. 아니요
맞춤 Parcelable app:argType="<type>", 여기서 <type>은 Parcelable의 정규화된 클래스 이름입니다. 기본값 '@null'을 지원합니다. 다른 기본값은 지원하지 않습니다. 아니요
맞춤 Serializable app:argType="<type>", 여기서 <type>은 Serializable의 정규화된 클래스 이름입니다. 기본값 '@null'을 지원합니다. 다른 기본값은 지원하지 않습니다. 아니요
맞춤 Enum app:argType="<type>", 여기서 <type>은 enum의 정규화된 이름입니다. 예 - 기본값은 정규화되지 않은 이름과 일치해야 합니다(예: 'SUCCESS'가 MyEnum.SUCCESS와 일치). 아니요 아니요

인수 유형이 null 값을 지원하는 경우 android:defaultValue="@null"을 사용하여 기본값을 null로 선언할 수 있습니다.

경로, 딥 링크 및 인수가 포함된 URI를 문자열에서 파싱할 수 있습니다. 이전 표에서처럼 Parcelable 및 Serializable과 같은 맞춤 데이터 유형을 사용하는 것은 불가능합니다. 맞춤 복합 데이터를 전달하려면 ViewModel 또는 데이터베이스와 같은 다른 위치에 데이터를 저장하고 탐색 중에 식별자만 전달한 다음 탐색이 완료된 후 새로운 위치에서 데이터를 회수합니다.

맞춤 유형 중 하나를 선택하면 Select Class 대화상자가 표시되고 선택한 유형에 상응하는 클래스를 선택하라는 메시지가 표시됩니다. Project 탭을 사용하면 현재 프로젝트에서 클래스를 선택할 수 있습니다.

<inferred type>을 선택하여 제공된 값에 기반해 탐색 라이브러리가 유형을 결정하도록 할 수 있습니다.

Array를 확인하여 인수가 선택된 Type 값의 배열이어야 함을 나타낼 수 있습니다. 다음 내용을 참고하세요.

  • enum 배열과 리소스 참조 배열은 지원되지 않습니다.
  • 기본 유형이 null을 허용하는 값을 지원하는지와 상관없이 배열은 null을 허용하는 값을 지원합니다. 예를 들어 app:argType="integer[]"를 사용하면 app:nullable="true"를 사용하여 null 배열 전달이 허용됨을 나타낼 수 있습니다.
  • 배열은 단일 기본값 '@null'을 지원합니다. 배열은 다른 기본값을 지원하지 않습니다.

작업에서 대상 인수 재정의

대상 레벨 인수 및 기본값은 대상을 탐색하는 모든 작업에서 사용됩니다. 필요한 경우 작업 레벨에서 인수를 정의하여 인수의 기본값을 재정의하거나 존재하지 않는 경우 설정할 수 있습니다. 이 인수는 대상에서 선언된 인수와 동일한 이름과 유형이어야 합니다.

다음 XML은 이전 예의 대상 수준 인수를 재정의하는 인수로 작업을 선언합니다.

<action android:id="@+id/startMyFragment"
    app:destination="@+id/myFragment">
    <argument
        android:name="myArg"
        app:argType="integer"
        android:defaultValue="1" />
</action>

Safe Args를 사용하여 유형 안전성을 갖춘 데이터 전달

탐색 구성요소에는 Safe Args라는 Gradle 플러그인이 있어서 모든 연결된 인수에 유형 안전성을 갖춘 탐색 및 액세스를 하기 위한 간단한 객체 및 빌더 클래스를 생성합니다. Safe Args는 유형 안전성을 보장하므로 데이터를 탐색하고 전달할 때는 Safe Args를 사용하는 것이 좋습니다.

Gradle을 사용하지 않는 경우 Safe Args 플러그인을 사용할 수 없습니다. 이럴 때는 번들을 사용하여 직접 데이터를 전달하면 됩니다.

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

Groovy

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

Kotlin

buildscript {
    repositories {
        google()
    }
    dependencies {
        val nav_version = "2.7.7"
        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를 사용 설정하면 생성된 코드에는 각 송수신 대상뿐만 아니라 각 작업의 다음과 같은 유형의 안전 클래스와 메서드가 포함됩니다.

  • 작업이 시작되는 각 대상에 클래스가 만들어집니다. 클래스 이름은 'Directions'라는 단어가 추가된 발신 대상 이름입니다. 예를 들어 발신 대상이 SpecifyAmountFragment라는 프래그먼트인 경우 생성된 클래스의 이름은 SpecifyAmountFragmentDirections입니다.

    이 클래스에는 발신 대상에서 정의된 각 작업의 메서드가 있습니다.

  • 인수를 전달하는 데 사용되는 각 작업의 경우 작업에 기반한 이름으로 내부 클래스가 만들어집니다. 예를 들어 작업 이름이 confirmationAction,이라면 클래스 이름은 ConfirmationAction입니다. 작업에 defaultValue가 없는 인수가 포함되면 연결된 작업 클래스를 사용하여 인수 값을 설정합니다.

  • 수신 대상에 클래스가 만들어집니다. 클래스 이름은 'Args'라는 단어가 추가된 대상 이름입니다. 예를 들어 대상 프래그먼트의 이름이 ConfirmationFragment,라면 생성된 클래스 이름은 ConfirmationFragmentArgs입니다. 이 클래스의 fromBundle() 메서드를 사용하여 인수를 검색합니다.

다음 예에서는 이러한 메서드를 사용하여 인수를 설정하고 navigate() 메서드에 전달하는 방법을 보여줍니다.

Kotlin

override fun onClick(v: View) {
   val amountTv: EditText = view!!.findViewById(R.id.editTextAmount)
   val amount = amountTv.text.toString().toInt()
   val action = SpecifyAmountFragmentDirections.confirmationAction(amount)
   v.findNavController().navigate(action)
}

Java

@Override
public void onClick(View view) {
   EditText amountTv = (EditText) getView().findViewById(R.id.editTextAmount);
   int amount = Integer.parseInt(amountTv.getText().toString());
   ConfirmationAction action =
           SpecifyAmountFragmentDirections.confirmationAction();
   action.setAmount(amount);
   Navigation.findNavController(view).navigate(action);
}

수신 대상 코드에서 getArguments() 메서드를 사용하여 번들을 검색하고 그 콘텐츠를 사용합니다. -ktx 종속 항목을 사용할 때 Kotlin 사용자는 by navArgs() 속성 위임을 사용하여 인수에 액세스할 수도 있습니다.

Kotlin

val args: ConfirmationFragmentArgs by navArgs()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val tv: TextView = view.findViewById(R.id.textViewAmount)
    val amount = args.amount
    tv.text = amount.toString()
}

Java

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    TextView tv = view.findViewById(R.id.textViewAmount);
    int amount = ConfirmationFragmentArgs.fromBundle(getArguments()).getAmount();
    tv.setText(amount + "");
}

전역 작업으로 Safe Args 사용

전역 작업으로 Safe Args를 사용할 때 다음 예와 같이 루트 <navigation> 요소에 android:id 값을 제공해야 합니다.

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/main_nav"
            app:startDestination="@id/mainFragment">

    ...

</navigation>

탐색은 android:id 값에 기반한 <navigation> 요소의 Directions 클래스를 생성합니다. 예를 들어 android:id=@+id/main_nav 값이 있는 <navigation> 요소가 있다면 생성된 클래스 이름은 MainNavDirections가 됩니다. <navigation> 요소 내의 모든 대상은 이전 섹션에서 설명한 것과 동일한 메서드를 사용하여 연결된 모든 전역 작업에 액세스하는 메서드를 생성했습니다.

번들 객체로 대상 간 데이터 전달

Gradle을 사용하지 않는 경우 Bundle 객체를 사용하여 대상 간에 계속 인수를 전달할 수 있습니다. 다음 예와 같이 Bundle 객체를 만들고 navigate()를 사용하여 대상에 전달합니다.

Kotlin

val bundle = bundleOf("amount" to amount)
view.findNavController().navigate(R.id.confirmationAction, bundle)

Java

Bundle bundle = new Bundle();
bundle.putString("amount", amount);
Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);

수신 대상 코드에서 getArguments() 메서드를 사용하여 Bundle를 검색하고 그 콘텐츠를 사용합니다.

Kotlin

val tv = view.findViewById<TextView>(R.id.textViewAmount)
tv.text = arguments?.getString("amount")

Java

TextView tv = view.findViewById(R.id.textViewAmount);
tv.setText(getArguments().getString("amount"));

시작 대상에 데이터 전달

앱의 시작 대상에 데이터를 전달할 수 있습니다. 먼저 데이터를 보유하는 Bundle을 명시적으로 구성해야 합니다. 그런 다음, 다음 접근 방식 중 하나를 사용하여 Bundle를 시작 대상에 전달합니다.

시작 대상에서 데이터를 검색하려면 Fragment.getArguments()를 호출합니다.

ProGuard 고려사항

코드를 축소하는 경우 Parcelable, Serializable, Enum 클래스 이름이 축소 프로세스 중에 난독화되지 않도록 해야 합니다. 다음 두 가지 방법 중 하나로 이 작업을 실행할 수 있습니다.

  • @Keep 주석을 사용하세요.
  • keepnames 규칙을 사용합니다.

다음 하위 섹션에서는 이러한 접근 방식을 설명합니다.

@Keep 주석 사용

다음 예에서는 모델 클래스 정의에 @Keep 주석을 추가합니다.

Kotlin

@Keep class ParcelableArg : Parcelable { ... }

@Keep class SerializableArg : Serializable { ... }

@Keep enum class EnumArg { ... }

Java

@Keep public class ParcelableArg implements Parcelable { ... }

@Keep public class SerializableArg implements Serializable { ... }

@Keep public enum EnumArg { ... }

keepnames 규칙 사용

또한 다음 예에서와 같이 keepnames 규칙을 proguard-rules.pro 파일에 추가할 수도 있습니다.

proguard-rules.pro

...

-keepnames class com.path.to.your.ParcelableArg
-keepnames class com.path.to.your.SerializableArg
-keepnames class com.path.to.your.EnumArg

...

추가 리소스

탐색에 관한 자세한 내용은 다음 추가 리소스를 참고하세요.

샘플

Codelab

동영상