How I can retrieve current fragment in NavHostFragment?

47,183

Solution 1

Reference to the displayed fragment (AndroidX):

java

public Fragment getForegroundFragment(){
    Fragment navHostFragment = getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
    return navHostFragment == null ? null : navHostFragment.getChildFragmentManager().getFragments().get(0);
}

kotlin

val navHostFragment: Fragment? =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
navHostFragment?.childFragmentManager?.fragments?.get(0)

Here nav_host_fragment is an ID of the fragment tag in your activity_main.xml with android:name="androidx.navigation.fragment.NavHostFragment"

Solution 2

Navigation does not provide any mechanism for getting the implementation (i.e., the Fragment itself) of the current destination.

As per the Creating event callbacks to the activity, you should either communicate with your Fragment by

  • Having the Fragment register a callback in its onAttach method, casting your Activity to an instance of an interface you provide
  • Use a shared ViewModel that your Activity and Fragment use to communicate.

Solution 3

You can do something like this:

  override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        val navHostFragment = supportFragmentManager.fragments.first() as? NavHostFragment
        if(navHostFragment != null) {
            val childFragments = navHostFragment.childFragmentManager.fragments
            childFragments.forEach { fragment ->
                fragment.onActivityResult(requestCode, resultCode, data)
            }
        }
    }

But for more advanced communication Listeners with callback methods registered in Fragment.onAttach() (Fragment -> Activity rather one direction communication) and SharedViewModel (bidirectional, important to have ViewModelProviders, and Lifecycle owner that is scoped to getActivity() rather)

Solution 4

Based on other answers

Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment();
Fragment fragment = navHostFragment.getChildFragmentManager().getFragments().get(0);

((Your Fragment Class) fragment).(public method inside the fragment)

worked for me

Solution 5

Using Michal's answer I wrote this extension function for testing:

@Suppress("UNCHECKED_CAST")
fun <F : Fragment> AppCompatActivity.getFragment(fragmentClass: Class<F>): F? {
    val navHostFragment = this.supportFragmentManager.fragments.first() as NavHostFragment

    navHostFragment.childFragmentManager.fragments.forEach {
        if (fragmentClass.isAssignableFrom(it.javaClass)) {
            return it as F
        }
    }

    return null
}

Used like this:

val myFragment = activity.getFragment(MyFragment::class.java)
Share:
47,183
BenjaminBihr
Author by

BenjaminBihr

Updated on July 09, 2022

Comments

  • BenjaminBihr
    BenjaminBihr almost 2 years

    I tried to find a method in the new Navigation components but I didn't find anything about that.

    I have the current destination with :

    mainHostFragment.findNavController().currentDestination
    

    But I can't get any reference to the displayed fragment.

  • Sever
    Sever about 5 years
    All links show how to communicate between fragments. But how we can call fragment method from activity if navigation does not provide any mechanism for getting the implementation of the current destination?
  • ianhanniballake
    ianhanniballake about 5 years
    @Sever - see this issue and how to use getPrimaryNavigationFragment() to retrieve the current Fragment.
  • Sever
    Sever about 5 years
    Big thanks. It works. val navHostFragment = supportFragmentManager.primaryNavigationFragment as NavHostFragment val yourFragment = currentFragmentClassName.childFragmentManager.primaryNavigat‌​ionFragment as YourFragment
  • drdaanger
    drdaanger over 4 years
    You can squish this down to inline fun <reified T : Fragment> FragmentManager.findFragmentByClass(): T? = fragments.firstOrNull { it is T } as T?
  • isabsent
    isabsent over 4 years
    @ianhanniballake: Sorry, I didn't understand is there a way to get the foreground fragment by means of getPrimaryNavigationFragment() now or they are going to provide such opportunity in the future only!?
  • Miha_x64
    Miha_x64 about 3 years
    Well, to share ViewModel between two fragments, one of them must be its owner. And the other one must find that owner in order to fetch that ViewModel. So… just never use Navigation, it's retarded.
  • carl
    carl about 3 years
    It is incomprehensible why Navigation does not maintain a list of fragments, for example needed when MainActivity wants to call a method in a child fragment. In consequence, you need to use the "good old ways" for that, and then, whats the point of introducing a Navigation system? I don@t get it.
  • Shalbert
    Shalbert over 2 years
    You can remove as? NavHostFragment and make the if-statement if (navHostFragment is NavHostFragment)
  • Milad Faridnia
    Milad Faridnia almost 2 years
    in my case ?.childFragmentManager?.fragments?.last() gives me current fragment
  • John Glen
    John Glen almost 2 years
    Wow, hacky answers. childFragmentManager.findFragmentById exists.