ナビゲーション グラフを設計する

Navigation コンポーネントは、ナビゲーション グラフを使用してアプリのナビゲーションを管理します。ナビゲーション グラフは、アプリ内のすべてのデスティネーションとともに、ユーザーがデスティネーション間を移動する際にたどる可能性がある論理的な道筋(アクション)を格納するリソース ファイルです。Android Studio の Navigation Editor を使用して、アプリのナビゲーション グラフを管理できます。

このトピックでは、アプリのナビゲーション グラフを設計する際のベスト プラクティスと推奨事項について説明します。

トップレベル ナビゲーション グラフ

アプリのトップレベル ナビゲーション グラフは、ユーザーがアプリを起動したときに最初に表示される開始デスティネーションから始まり、ユーザーがアプリ内を移動する際に表示されるすべてのデスティネーションを含む必要があります。

図 1. トップレベル ナビゲーション グラフ

ネストグラフ

一般的に、アプリ内のログインフロー、ウィザード、その他のサブフローは、ネストされたナビゲーション グラフとして表現するのが最も適切です。このように自己完結型のサブナビゲーション フローをネストすることにより、アプリの UI のメインフローの把握と管理が容易になります。また、ネストグラフは再利用可能です。さらに、一定レベルのカプセル化も実現できます。ネストグラフの外部にあるデスティネーションは、ネストグラフの内部にあるデスティネーションに直接アクセスすることができません。代わりに、navigate() を使用して、ネストグラフ自体にアクセスする必要があります。ネストグラフの内部ロジックは、グラフの残りの部分に影響を与えることなく変更できます。

図 1 のトップレベル ナビゲーション グラフの例で、ユーザーがアプリを初めて起動したときに限り、title_screen 画面と register 画面を表示したいとします。さらに、ユーザー情報を保存して、次回以降のアプリの起動時には、直接 match 画面にユーザーを誘導するとします。ベスト プラクティスとしては、match 画面をトップレベル ナビゲーション グラフの開始デスティネーションに設定し、title_screen 画面と register 画面をネストグラフに移動するのが適切です。図 2 をご覧ください。

図 2. ネストグラフが追加されたトップレベル ナビゲーション グラフ

match 画面が起動したら、登録済みユーザーがいるかどうかをチェックします。ユーザーが登録されていない場合は、ユーザーを register 画面に誘導します。条件付きナビゲーション シナリオの詳細については、条件付きナビゲーションをご覧ください。

グラフ構造をモジュール化するもう 1 つの方法は、親ナビゲーション グラフ内の <include> 要素を介して、別のグラフを子グラフとして組み込むことです。この方法では、組み込まれる側のグラフを独立したモジュールまたはプロジェクト内で定義できるため、最大限の再利用可能性を実現できます。

ライブラリ モジュール間のナビゲーション

ナビゲーション グラフを格納するライブラリ モジュールにアプリが依存している場合は、<include> 要素を使用して、それらのナビゲーション グラフを参照できます。

詳しくは、マルチモジュール プロジェクトのナビゲーションに関するベスト プラクティスをご覧ください。

グローバル アクション

アプリのデスティネーションに到達できるパスが複数ある場合、そのデスティネーションに移動するためのグローバル アクションを定義する必要があります。グローバル アクションを利用すると、どこからでも対象のデスティネーションに移動できるようになります。

グローバル アクションを上記のライブラリ モジュール サンプルに適用してみましょう。このサンプルでは、results_winner デスティネーションと game_over デスティネーションの両方に対して同じアクションが定義されています。この共通アクションを単一のグローバル アクションとして抽出し、両方のデスティネーションから参照するようにします。以下の例をご覧ください。

<?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"
   android:id="@+id/in_game_nav_graph"
   app:startDestination="@id/in_game">

   <!-- Action back to destination which launched into this in_game_nav_graph-->
   <action android:id="@+id/action_pop_out_of_game"
                       app:popUpTo="@id/in_game_nav_graph"
                       app:popUpToInclusive="true" />

   <fragment
       android:id="@+id/in_game"
       android:name="com.example.android.gamemodule.InGame"
       android:label="Game">
       <action
           android:id="@+id/action_in_game_to_resultsWinner"
           app:destination="@id/results_winner" />
       <action
           android:id="@+id/action_in_game_to_gameOver"
           app:destination="@id/game_over" />
   </fragment>

   <fragment
       android:id="@+id/results_winner"
       android:name="com.example.android.gamemodule.ResultsWinner" />

   <fragment
       android:id="@+id/game_over"
       android:name="com.example.android.gamemodule.GameOver"
       android:label="fragment_game_over"
       tools:layout="@layout/fragment_game_over" />

</navigation>

フラグメント内でグローバル アクションを使用する方法の詳細と例については、ナビゲーション ドキュメントのグローバル アクションをご覧ください。