デスティネーションへの移動は、NavHost
内でアプリ ナビゲーションを管理するオブジェクトである NavController
を使用して実行されます。各 NavHost
は、それぞれ独自の NavController
を持ちます。NavController
は、デスティネーションに移動するための方法を複数提供します。この点については、以下のセクションで説明します。
フラグメントや、アクティビティ、ビューの NavController
を取得するには、以下のいずれかの方法を使用します。
Kotlin:
Java:
NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
NavController
を取得した後、navigate()
のいずれかのオーバーロードを呼び出すことで、デスティネーション間を移動できます。各オーバーロードは、さまざまなナビゲーション シナリオをサポートします。詳細については、以下のセクションをご覧ください。
Safe Args を使用してタイプセーフに移動する
デスティネーション間を移動する際は、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") } }
また、使用可能な 2 つのプラグインのいずれかを適用する必要があります。
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 を有効にすると、定義した各アクション用のクラスとメソッド、ならびに送信側と受信側の各デスティネーションに対応するクラスを格納したコードが生成されます。
Safe Args は、アクションの発生元となる送信側デスティネーションごとにクラスを生成します。生成されるクラス名は、送信側デスティネーションのクラス名に「Directions」という語を追加したものになります。たとえば、送信側デスティネーションが「SpecifyAmountFragment
」という名前の場合、「SpecifyAmountFragmentDirections
」という名前のクラスが生成されます。
生成されるクラスには、送信側デスティネーション内で定義されている各アクション用の静的メソッドが格納されます。このメソッドは、定義済みのアクション パラメータを引数として受け取り、NavDirections
オブジェクトを返します。このオブジェクトは直接 navigate()
に渡すことができます。
Safe Args の例
たとえば、SpecifyAmountFragment
と ConfirmationFragment
という 2 つのデスティネーションを接続する単一のアクションを持つナビゲーション グラフがあるとします。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) }
Java
@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) }
Java
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))
Java
button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null));
トップ アプリバーやボトム ナビゲーションなど、他の一般的な UI コンポーネントの処理方法については、NavigationUI を使用して UI コンポーネントを更新するをご覧ください。
アクションにナビゲーション オプションを提供する
ナビゲーション グラフ内でアクションを定義すると、Navigation コンポーネントは、それに対応する NavAction
クラスを生成します。このクラスには、対象のアクション用に定義された以下のような構成が格納されます。
- デスティネーション: ターゲット デスティネーションのリソース ID。
- デフォルト引数: ターゲット デスティネーションのデフォルト値を格納する
android.os.Bundle
(指定されている場合)。 - ナビゲーション オプション:
NavOptions
として表現されるナビゲーション オプション。このクラスには、アニメーション リソース構成や、ポップ動作、デスティネーションをシングルトップ モードで起動するかどうかの設定など、ターゲット デスティネーションとの間の遷移に関する特別な構成がすべて格納されます。
2 つの画面で構成され、一方の画面から他方の画面へ移動するアクションを持つグラフの例について考えてみましょう。
<?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)
Java
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)
Java
NavDeepLinkRequest request = NavDeepLinkRequest.Builder .fromUri(Uri.parse("android-app://androidx.navigation.app/profile")) .build() NavHostFragment.findNavController(this).navigate(request)
NavDeepLinkRequest
に加えて、Uri
でもアクションと MIME タイプのディープリンクがサポートされています。リクエストにアクションを追加するには、fromAction()
または setAction()
を使用します。MIME タイプをリクエストに追加するには、fromMimeType()
または setMimeType()
を使用します。
NavDeepLinkRequest
を暗黙的ディープリンク デスティネーションに適切に一致させるには、URI、アクション、MIME タイプをすべてデスティネーションの NavDeepLink
に一致させる必要があります。URI はパターンが一致しており、アクションは完全に一致している必要があります。また、MIME タイプは相互に関連している必要があります(たとえば「image/jpg」は「image/*」と一致します)。
アクション ID やデスティネーション 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() }
Java
... if (!navController.popBackStack()) { // Call finish() on your Activity finish(); }
popUpTo と popUpToInclusive
アクションを使用して移動する場合、必要に応じて、追加のデスティネーションをバックスタックからポップできます。たとえば、アプリに初期ログインフローがある場合、一度ユーザーがログインした後は、[戻る] ボタンをタップしてもログインフローに戻ることがないように、ログイン関連デスティネーションをすべてバックスタックからポップする必要があります。
デスティネーション間を移動する際にデスティネーションをポップするには、対象の<action>
要素に app:popUpTo
属性を追加します。app:popUpTo
は、Navigation ライブラリに対し、navigate()
呼び出しの一環として、バックスタックからいくつかのデスティネーションをポップするように指示します。属性値として、スタック上に残す最も新しいデスティネーションの ID を指定します。
app:popUpToInclusive="true"
を追加すると、app:popUpTo
内で指定したデスティネーションもバックスタックから削除するように指示できます。
popUpTo の例: 循環型ロジック
アプリに A、B、C という 3 つのデスティネーションがあり、A から B、B から C、C から A に移動するアクションを持っているとします。対応するナビゲーション グラフを図 1 に示します。
図 1:3 つのデスティネーション(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)のインスタンスが 1 つずつ含まれています。デスティネーション A に戻るとき、A を基準に popUpTo
を実行します。つまり、このナビゲーション中に B と C をスタックから削除します。また、app:popUpToInclusive="true"
を使用することで、最初の A もスタックからポップされ、実質的にスタックがクリアされます。app:popUpToInclusive
を使用しなかった場合、バックスタックにはデスティネーション A のインスタンスが 2 つ格納されることになります。