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

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() }
    ),
    // ...
)

ResultEventBusNavEntryDecorator を使用して結果を渡す

Navigation 3 1.2.0 以降では、ResultEventBusNavEntryDecorator を使用して、LocalResultEventBus 構成ローカルを使用して各 NavEntryResultEventBus を提供できます。

デフォルトでは、rememberResultEventBusNavEntryDecoratorrememberResultEventBus を使用して内部的に独自の ResultEventBus インスタンスを作成して記憶します。デコレータ階層の外側(トップレベルのアプリ スキャフォールディングなど)でイベントバスにアクセスする必要がある場合は、rememberResultEventBus を呼び出して ResultEventBus をホイストし、rememberResultEventBusNavEntryDecorator(resultEventBus) に渡すことができます。

val resultEventBus = rememberResultEventBus()

NavDisplay(
    /* ... */
    entryDecorators = listOf(
        rememberSaveableStateHolderNavEntryDecorator(),
        rememberResultEventBusNavEntryDecorator(resultEventBus = resultEventBus)
    )
)

結果の送信とモニタリングについて詳しくは、結果を返すをご覧ください。

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

デコレータを使用して、次のことを行います。

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

デコレータは次の目的で使用しないでください。

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

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

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