Search code examples
androidandroid-fragmentsandroid-architecture-navigationandroid-jetpack-compose

Use NavHostFragment in Jetpack Compose


We have a legacy app that we start migrating to Jetpack Compose. The app has a single activity, uses Navigation component with a navigation XML graph to navigate between fragments.

We are following this approach:

  • Migrate each fragment one at a time
  • For each fragment make a @Composable screen that provides the same UI as the fragment
  • From the fragment onCreateView() set the content to the newly created screen

Now, say we had Fragment1 containing some action to navigate to Fragment2. In the original code we would call the following in Fragment1:

NavHostFragment.findNavController(this).navigate(directionToFragment2)

When creating a composable to replace Fragment1 UI, how can we implement the navigation from this composable to Fragment2? In the composable we can call:

val navController = rememberNavController()

But this seems to be a different navigation controller than the one used by the fragments. Is there a way from a composable to get access to the same navigation controller as the one used by the fragment?

The only alternative we currently see is to pass the Fragment's navigation controller as a parameter to the composable, but it doesn't look quite right.


Solution

  • You are correct that you cannot use rememberNavController() - that will create a completely new nested NavController suitable only for composable destinations.

    As per the testing guide, it is strongly recommended to avoid any direct references to any NavController within any of your composables themselves (i.e., a HomeScreen composable). Instead, the recommendation is to pass in a lambda that your composable can trigger when it wants to navigate.

    Your Fragment (the one calling setContent on your ComposeView) would then be responsible for implementing that lambda and calling NavHostFragment.findNavController(this).navigate(directionToFragment2).

    As a (less recommended) alternative, you can also use LocalView.current.findNavController() as Fragments populate the NavController at the view level as well and LocalView points to the ComposeView hosting your Composable.