Set start destination for NavhostFragment dynamically?

Anoop Gopalakrishnan
4 min readNov 15, 2019

Does that sound interesting?.

Hmmm...

May be for some of you ,who just have started using the navigation components for the first time. 🤣

Okay, let's see what it is….

We recently started using navigation components in our project. I came across a scenario where I had to set different start destinations based on flag values.

I thought to take some space here to share the details if it might help someone who is trying it for the first time.

Think about the below use case.

  1. The company is changing their privacy policy.
  2. For an Existing User, the company wants them to go through the newly updated privacy policy and accept the terms and conditions and then show up the home screen.
  3. Once the new privacy policy is accepted during the login, the user should be taken directly to the home screen, in the future login sessions.

Let’s mock up this use case using the navigation controller.

Let’s code .

Setup navigation component dependencies.

Add navigation component’s dependencies to build.gradle file inside the app folder and sync the Gradle dependencies.

dependencies {
def nav_version = "2.1.0"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}

Setup navigation graph

  1. In the Project window, right-click on the res directory and select New > Android Resource File. The New Resource File dialog appears.
  2. Type a name in the File name field, such as “nav_graph”.
  3. Select Navigation from the Resource type drop-down list, and then click OK.

This will create a navigation resource directory within the res directory, with your navigation graph resource file nav_graph.xml

Adding destinations to the nav_graph

Use Navigation Editor to add destination to your nav graph

Press the Add destination button to create a new destination.

I will be creating two destinations based on our use case.

  1. NewPrivacyPolicyFragment
  2. HomeFragment

Switch to Text view to see the generated XML code.

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nav_graph"
app:startDestination="@id/newPrivacyPolicyFragment"
tools:ignore="UnusedNavigation">

<fragment android:id="@+id/newPrivacyPolicyFragment"
android:name="com.example.navcomponents.NewPrivacyPolicyFragment"
android:label="fragment_new_privacy_policy"
tools:layout="@layout/fragment_new_privacy_policy"/>
<fragment android:id="@+id/homeFragment"
android:name="com.example.navcomponents.HomeFragment"
android:label="fragment_home"
tools:layout="@layout/fragment_home"/>
</navigation>

Base activity to mock up two use cases

Now let’s create a base activity to mockup the above use cases. Nothing fancy here, just add two buttons to main_activity.xml. One for mocking up the user login, who has already accepted the privacy policy and the other, for the user who has not accepted the policy yet.

Add the below code to MainActivity.kt for handling the navigation to the NavigationActivity, based on the click action of the buttons

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button1.setOnClickListener {
NavigationActivity.open(this, true)
}
button2.setOnClickListener {
NavigationActivity.open(this, false)
}
}
}

Add the below code to NavigationActivity.kt to respond to the function calls from MainActivity.

NavigationActivity.kt has a static function open which takes two parameters. One is a Context and the another one is a boolean value, to say whether the user has already accepted the privacy policy. Pretty much straight forward.

class NavigationActivity: AppCompatActivity() {

companion object {
private const val IS_PRIVACY_POLICY_ACCEPTED="isPrivacyPolicyAccepted"
fun open(context: Context, isAcceptedNewPrivacyPolicies: Boolean) {
context.startActivity(Intent(context,NavigationActivity::class.java).apply {
putExtra(IS_PRIVACY_POLICY_ACCEPTED, isAcceptedNewPrivacyPolicies)
})
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.navigation_activity)
}
}

Setup navigation_activity.xml with NavHostFragment

Now we are gonna set up our NavHostFragment that holds our navigation graph, which we have created using the previous steps.

Add the below code to the navigation_activity.xml file. This NavHostFragment needs app:navGraph property ,which will be set through code.

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

Now the actual magic

Just add the below code to onCreate method of NavigationActivity

val navHostFragment = nav_host_fragment as NavHostFragment
val graphInflater = navHostFragment.navController.navInflater
navGraph = graphInflater.inflate(R.navigation.nav_graph)
navController = navHostFragment.navController

val
destination = if (intent.getBooleanExtra(
IS_PRIVACY_POLICY_ACCEPTED,
false
)
) R.id.homeFragment else R.id.newPrivacyPolicyFragment
navGraph.startDestination = destination
navController.graph = navGraph

So simple .

We have set the startDestination of our navGraph based on the IS_PRIVACY_POLICY_ACCEPTED value and have set the navController’s graph property to updated navGraph

That's it. Now run the code

You can find the full code here.

Thank You

--

--