To implement a robust navigation system, your app needs a centralized way to
handle back gestures and other navigation signals. This page describes how to
use NavigationEventDispatcher to coordinate and distribute these
navigation events across your application.
Declare a NavigationEventDispatcher
The NavigationEventDispatcher is the central component of the
NavigationEvent library. It acts as an event hub that dispatches
navigation-related events, such as back gestures and navigation transitions, to
registered listeners within your app. Components can subscribe to these events
to react to navigation changes or other system-driven navigation actions.
You should provide NavigationEventDispatcher instances through a
NavigationEventDispatcherOwner. This ensures that different parts of your
app can access the same dispatcher and observe navigation events in a consistent
and coordinated way.
class MyComponent: NavigationEventDispatcherOwner { override val navigationEventDispatcher: NavigationEventDispatcher = NavigationEventDispatcher() }
If you are inside of a ComponentActivity, instead of implementing your own
dispatcher, you can retrieve the one provided for you.
class MyCustomActivity : ComponentActivity() { fun addMyHandler() { // navigationEventDispatcher provided by the ComponentActivity navigationEventDispatcher.addHandler(myNavigationEventHandler) } }
Add a NavigationEventInput
Now that you've registered the handler, you are set up to receive events.
However, you need to provide a source from which the events are generated with
NavigationEventInput.
NavigationEventInput is the platform-specific component that receives
raw system input and translates it into a standard NavigationEvent to be sent
to the NavigationEventDispatcher.
The following example is a custom implementation of a NavigationEventInput:
public class MyInput : NavigationEventInput() { @MainThread public fun backStarted(event: NavigationEvent) { dispatchOnBackStarted(event) } @MainThread public fun backProgressed(event: NavigationEvent) { dispatchOnBackProgressed(event) } @MainThread public fun backCancelled() { dispatchOnBackCancelled() } @MainThread public fun backCompleted() { dispatchOnBackCompleted() } }
Next, provide that input to your dispatcher:
navigationEventDispatcher.addInput(MyInput())
Clean up resources with dispose()
To prevent memory leaks in a dynamic UI, every created
NavigationEventDispatcher instance must be explicitly removed from the
hierarchy using the dispose() method when the component it is tied to is
destroyed:
navigationEventDispatcher.dispose()
The dispose() method ensures a cascading cleanup by iteratively removing
the dispatcher and all of its descendants (children and grandchildren),
guaranteeing that all associated handlers are unregistered from the shared
system.
Dispatcher hierarchy and control
The NavigationEventDispatcher supports a parent-child hierarchy, enabling
components nested deep within a UI (such as nested NavHosts or dialogs) to
participate in navigation event handling.
Create a child dispatcher
A child dispatcher is created by passing a reference to its parent dispatcher
during construction. All dispatchers in a hierarchy share the same
NavigationEventProcessor to maintain a global Last-In, First-Out (LIFO)
event ordering based on priority.
Hierarchical enabling
The dispatcher includes an isEnabled property that allows developers to enable
or disable an entire subtree of handlers at once.
When a parent dispatcher is disabled (isEnabled = false), all handlers
associated with that parent and any of its children will be ignored, regardless
of their individual enabled state.