宛先にロジックまたはラッパーを適用する

NavEntryDecorator クラスを使用すると、追加情報を提供したり、同じロジックをリンク先に適用したりできます。このクラスは、バックスタック内の各 NavEntry をコンポーザブル関数でラップします。つまり、エントリのコンテンツを装飾します。

カスタム デコレータを作成する

デコレータを作成するには、NavEntryDecorator クラスを拡張し、次のメソッドをオーバーライドします。

  • decorate - バックスタック内の各 NavEntry に対して呼び出されるコンポーザブル ラムダ。NavEntry をパラメータとして受け取ります。これにより、エントリの contentKey にキー設定された状態オブジェクトを作成できます。CompositionLocalProvider を使用して、エントリのコンテンツに依存関係を指定できます。コンテンツをコンポーザブル関数で囲んだり、副作用をトリガーしたりすることもできます。このメソッド内では、必ず entry.Content() を呼び出す必要があります。
  • onPop - NavEntry がバックスタックから削除され、コンポジションから離れたときに呼び出されるコールバック。削除されたエントリの contentKey を受け取ります。contentKey を使用して、そのエントリに関連付けられた状態を特定してクリーンアップします。

次の例では、NavEntryDecorator クラスを拡張してカスタム デコレータを作成します。

// import androidx.navigation3.runtime.NavEntryDecorator
class CustomNavEntryDecorator<T : Any> : NavEntryDecorator<T>(
    decorate = { entry ->
        Log.d("CustomNavEntryDecorator", "entry with ${entry.contentKey} entered composition and was decorated")
        entry.Content()
    },
    onPop = { contentKey -> Log.d("CustomNavEntryDecorator", "entry with $contentKey was popped") }
)

デコレータで状態にアクセスする必要がある場合は、その状態を作成するコンポーズ可能な関数を作成し、それを使用してデコレータを構築します。実装例については、rememberSaveableStateHolderNavEntryDecorator のソースコードをご覧ください。これにより、状態(SaveableStateHolder)が作成され、それを使用してデコレータが構築されます。

バックスタックを装飾する

NavEntryDecorator を作成したら、次のいずれかの方法でバックスタックのエントリを装飾します。

  • rememberDecoratedNavEntries を使用します。この関数は、複数のバックスタックがあり、それぞれに独自のデコレータのセットがある場合に便利です(詳しくは、こちらのコードレシピをご覧ください)。この関数は、NavDisplay で使用できる NavEntry の装飾されたリストを返します。
  • entryDecorators パラメータを使用して、デコレータを NavDisplay に直接指定します。NavDisplay は内部で rememberDecoratedNavEntries を呼び出し、装飾されたエントリを表示します。

デフォルトのデコレータを含める

Navigation 3 には、NavEntry の状態を構成の変更やプロセスの終了後も保持できるようにする SaveableStateHolderNavEntryDecorator という名前のデフォルトのデコレータが含まれています。NavEntry コンテンツを SaveableStateProvider でラップし、NavEntry コンテンツ内の rememberSaveable 呼び出しが正しく機能するようにします。

デコレータが SaveableStateProvider を提供していない限り、提供されるデコレータのリストの最初のデコレータとして SaveableStateHolderNavEntryDecorator を含める必要があります。これは rememberSaveableStateHolderNavEntryDecorator を使用して作成されます。

次に例を示します。

// import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
NavDisplay(
    entryDecorators = listOf(
        rememberSaveableStateHolderNavEntryDecorator(),
        remember { CustomNavEntryDecorator() }
    ),
    // ...
)

デコレータを使用するタイミング

デコレータを使用して、次のことができます。

  • バックスタック内のすべての NavEntry の依存関係を作成します。たとえば、ViewModelStoreNavEntryDecorator はすべての NavEntry に対して ViewModelStore を作成します。
  • オブジェクトを複数の NavEntry にスコープ設定します。たとえば、複数のエントリ間で ViewModel を共有する場合などです。
  • 複数の NavEntry に対して同じアクションを実行します。たとえば、各エントリに対してロギング、デバッグ、トレース オペレーションを実行します。
  • 同じコンポーズ可能な関数で NavEntry をラップします。
  • NavEntry に関連付けられている状態をクリーンアップします。たとえば、バックスタックからエントリが削除されると、ViewModelStoreNavEntryDecorator は関連付けられた ViewModelStore をクリアします。

デコレータを使用して次のことは行わないでください。

  • 依存関係を 1 つの NavEntry に渡します。
  • バックスタックよりも広いスコープの依存関係を提供します。

どちらの場合も、代わりに NavEntry を作成するときに依存関係を直接渡します。

その他のコード例については、NavEntryDecorator をご覧ください。