Navigation では、デスティネーションの引数を定義して、ナビゲーション オペレーションにデータをアタッチできます。たとえば、ユーザー プロフィールのデスティネーションでは、ユーザー ID 引数を受け取って、表示するユーザーを決定します。
一般に、デスティネーション間で渡すデータの量は、最小限に抑えることを強くおすすめします。たとえば、オブジェクト自体を渡すのではなく、オブジェクトを取得するためのキーを渡すようにします。これは、Android で保存済み状態のデータに使用できる合計容量が限られているためです。大量のデータを渡す必要がある場合は、ViewModel の概要で説明されているように ViewModel
を使用します。
デスティネーション引数を定義する
デスティネーション間でデータを渡すには、まず、引数を定義します。そのためには、次の手順に沿って、引数を受け取るデスティネーションに引数を追加します。
- Navigation Editor で、引数を受け取るデスティネーションをクリックします。
- [Attributes] パネルで [Add]([+])をクリックします。
- 表示された [Add Argument Link] ウィンドウで、引数名、引数の型、引数に null を指定できるかどうか、デフォルト値(必要な場合)を入力します。
- [Add] をクリックします。これで、[Attributes] パネルの [Arguments] リストに引数が表示されます。
- 次に、対応するアクションをクリックして、このデスティネーションに移動します。これで、[Attributes] パネルの [Argument Default Values] に、新たに追加した引数が表示されます。
XML でも、引数が追加されたことを確認できます。[Text] タブをクリックして XML ビューに切り替えると、引数を受け取るデスティネーションに引数が追加されていることを確認できます。以下に例を示します。
<fragment android:id="@+id/myFragment" > <argument android:name="myArg" app:argType="integer" android:defaultValue="0" /> </fragment>
サポートされている引数の型
Navigation ライブラリでは、以下の引数の型がサポートされています。
タイプ | app:argType の構文 | デフォルト値のサポート | ルートでの処理 | null 許容 |
---|---|---|---|---|
Integer | app:argType="integer" | はい | はい | × |
Float | app:argType="float" | はい | はい | × |
Long | app:argType="long" | ○ - デフォルト値は必ず接尾辞「L」で終わる必要があります(例: 「123L」)。 | はい | × |
Boolean | app:argType="boolean" | ○ - 「true」または「false」。 | はい | × |
String | 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 やデータベースなど別の場所にデータを格納し、ナビゲーション中は ID のみを渡して、ナビゲーションが完了した後に新しい場所でデータを取得します。
カスタム型のいずれかを選択した場合、[Select Class] ダイアログが表示され、その型に対応するクラスを選択するよう促されます。[Project] タブでは、現在のプロジェクトからクラスを選択できます。
<inferred type> を選択すると、Navigation ライブラリにより、指定した値に基づいて型が決められます。
引数に [Type] で選択した型の配列を使用する必要があることを示すには、[Array] チェックボックスをオンにします。次の点に注意してください。
- 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 を使用してタイプセーフにデータを渡す
Navigation コンポーネントには、Safe Args と呼ばれる Gradle プラグインが含まれています。Safe Args は、ナビゲーションや関連引数へのアクセスをタイプセーフに行うためのシンプルなオブジェクトとビルダークラスを生成します。Safe Args は型安全性が確保されているため、データの移動と受け渡しには強く推奨されます。
Gradle を使用していない場合は、Safe Args プラグインを使用できません。そのような場合は、Bundle を使用することで、データを直接渡すことができます。
如需将 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") } }
您还必须应用以下两个可用插件之一。
如需生成适用于 Java 模块或 Java 和 Kotlin 混合模块的 Java 语言代码,请将以下行添加到应用或模块的 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>
Navigation コンポーネントは、<navigation>
要素向けに android:id
値に基づく Directions
クラスを生成します。たとえば、<navigation>
要素に対して android:id=@+id/main_nav
が指定されている場合、「MainNavDirections
」という名前のクラスが生成されます。<navigation>
要素内のすべてのデスティネーションには、前のセクションで説明したものと同じメソッドにより、関連するすべてのグローバル アクションにアクセスするためのメソッドが生成されます。
Bundle オブジェクトを使用してリンク先間でデータを渡す
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
を開始デスティネーションに渡します。
NavHost
をプログラムで作成する場合は、NavHostFragment.create(R.navigation.graph, args)
を呼び出します。ここで、args
はデータを保持するBundle
です。- それ以外の場合は、以下の
NavController.setGraph()
のオーバーロードのいずれかを呼び出して、開始デスティネーション引数を設定します。- グラフの ID を使用します:
navController.setGraph(R.navigation.graph, args)
- グラフ自体を使用する:
navController.setGraph(navGraph, args)
- グラフの ID を使用します:
開始デスティネーション内でデータを取得するには、Fragment.getArguments()
を呼び出します。
ProGuard に関する注意事項
コードを圧縮する場合は、圧縮プロセスの一環として Parcelable
、Serializable
、Enum
のクラス名が難読化されないようにする必要があります。これには次の 2 つの方法があります。
- @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
...
参考情報
ナビゲーションについて詳しくは、以下の参考情報をご確認ください。