Fragments and the Kotlin DSL

The Navigation component provides a Kotlin-based domain-specific language, or DSL, that relies on Kotlin's type-safe builders . This API lets you declaratively compose your graph in your Kotlin code, rather than inside an XML resource. This can be useful if you want to build your app's navigation dynamically. For example, your app could download and cache a navigation configuration from an external web service and then use that configuration to dynamically build a navigation graph in your activity's onCreate() function.

Dependencies

To use the Kotlin DSL with Fragments, add the following dependency to your app's build.gradle file:

Groovy

dependencies {
    def nav_version = "2.10.1"

    api "androidx.navigation:navigation-fragment-ktx:$nav_version"
}

Kotlin

dependencies {
    val nav_version = "2.10.1"

    api("androidx.navigation:navigation-fragment-ktx:$nav_version")
}

Building a graph

Here is a basic example based on the Sunflower app. For this example, we have two destinations: home and plant_detail. The home destination is present when the user first launches the app. This destination displays a list of plants from the user's garden. When the user selects one of the plants, the app navigates to the plant_detail destination.

Figure 1 shows these destinations along with the arguments required by the plant_detail destination and an action, to_plant_detail, that the app uses to navigate from home to plant_detail.

The Sunflower app has two destinations along with an action that
            connects them.
Figure 1. The Sunflower app has two destinations, home and plant_detail, along with an action that connects them.

Hosting a Kotlin DSL Nav Graph

Before you can build your app's navigation graph, you need a place to host the graph. This example uses fragments, so it hosts the graph in a NavHostFragment inside of a FragmentContainerView:

<!-- activity_garden.xml -->
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true" />

</FrameLayout>

Notice that the app:navGraph attribute is not set in this example. The graph isn't defined as a resource in the res/navigation folder so it needs to be set as part of the onCreate() process in the activity.

In XML, an action ties together a destination ID with one or more arguments. However, when using the Navigation DSL a route can contain arguments as part of the route. This means that there is no concept of actions when using the DSL.

The next step is to define the routes that you will use when defining your graph.

Create routes for your graph

XML-based navigation graphs are parsed as part of the Android build process. A numeric constant is created for each id attribute defined in the graph. These build time generated static IDs are not available when building your navigation graph at runtime so the Navigation DSL uses serializable types instead of IDs. Each route is represented by a unique type.

When dealing with arguments, these are built into the route type. This lets you have type safety for your navigation arguments.

@Serializable data object Home
@Serializable data class Plant(val id: String)

Once you've defined your routes, you can build the navigation graph.

val navController = findNavController(R.id.nav_host_fragment)
navController.graph = navController.createGraph(
    startDestination = Home
) {
    fragment<HomeFragment, Home> {
        label