21

Anywhere in a NavHostFragment I can do findNavController().navigateUp()

Or, if in my Fragment I have a button to be used for navigation, I could do either:

editButton.setOnClickListener { v ->
    v.findNavController().navigateUp()
}

or

editButton.setOnClickListener {
    findNavController().navigateUp()
}

Why would I use one extension function vs the other when setting up a button click listener in a Fragment?

liminal
  • 1,144
  • 2
  • 13
  • 24

3 Answers3

18

They are almost the same, Fragment.findNavController() is just a handy shortcut, it actually calls Navigation.findNavController(view) at the end. Both of them are getting the NavController from the root view of the fragment.

// NavHostFragment.java
public static NavController findNavController(@NonNull Fragment fragment) {
    ....
    View view = fragment.getView();
    if (view != null) {
        return Navigation.findNavController(view);
    }
    ...
}
jaychang0917
  • 1,880
  • 1
  • 16
  • 21
  • Thanks for that. What about the code part above it that handles NavHostFragment differently? – liminal Sep 08 '18 at 02:28
  • afaik, there is no difference, they search for a `NavController` from the root view of the fragment. – jaychang0917 Sep 08 '18 at 02:39
  • I am thinking that one reason the view one would be preferred is a slight performance improvement as a result of using the view right away rather than doing the `NavHostFragment` checks first and then falling back on the view. – liminal Sep 08 '18 at 03:21
3

Thank you for the Java answer, I offer a ViewBinding solution in kotlin, doing the same

// NavHostFragment.kotlin
fun findMyNavController(@NonNull fragment: Fragment): NavController {
    return Navigation.findNavController(binding.root)
}
CryptoCode
  • 945
  • 6
  • 19
2

Although they are not identical as suggested by the top voted answer, the performance difference should be negligible in general scenarios. However if you use the v.findNavController() on a View which is deeply nested down, then you should prefer Fragment extension findNavController() as it will perform better.

In general I don't see any reason to prefer the v.findNavController over the Fragment extension. following is the complete code of this method from NavHostFragment and it only calls Navigation.findNavController if it doesn't find the NavController using the fragment

public static NavController findNavController(@NonNull Fragment fragment) {
    Fragment findFragment = fragment;
    while (findFragment != null) {
        if (findFragment instanceof NavHostFragment) {
            return ((NavHostFragment) findFragment).getNavController();
        }
        Fragment primaryNavFragment = findFragment.requireFragmentManager()
                 .getPrimaryNavigationFragment();
        if (primaryNavFragment instanceof NavHostFragment) {
            return ((NavHostFragment) primaryNavFragment).getNavController();
        }
        findFragment = findFragment.getParentFragment();
    }

    // Try looking for one associated with the view instead, if applicable
    View view = fragment.getView();
    if (view != null) {
        return Navigation.findNavController(view);
    }
    throw new IllegalStateException("Fragment " + fragment
                + " does not have a NavController set");
}
mightyWOZ
  • 7,946
  • 3
  • 29
  • 46