Android Navigation Architecture Component - Get current visible fragment

AndroidAndroid NavigationAndroid Jetpack

Android Problem Overview


Before trying the Navigation component I used to manually do fragment transactions and used the fragment tag in order to fetch the current fragment.

val fragment:MyFragment = supportFragmentManager.findFragmentByTag(tag):MyFragment

Now in my main activity layout I have something like:

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

How can I retrieve the current displayed fragment by the Navigation component? Doing

supportFragmentManager.findFragmentById(R.id.nav_host)

returns a NavHostFragment and I want to retrieve my shown 'MyFragment`.

Thank you.

Android Solutions


Solution 1 - Android

I managed to discover a way for now and it is as follows:

NavHostFragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host);
navHostFragment.getChildFragmentManager().getFragments().get(0);

In case of course you know it is the first fragment. I am still investigating a way without this. I agree it is not the best way but that should be something for now.

Solution 2 - Android

There is no way I can find to retrieve the current fragment instance. However, you can get the ID of lastly added fragment using the code below.

navController.currentDestination?.getId()

It returns the ID in navigation file. Hope this helps.

Solution 3 - Android

You should look the childFragmentManager primaryNavigationFragment property of your nav fragment, this is where the current displayed fragment is referenced.

val navHost = supportFragmentManager.findFragmentById(R.id.main_nav_fragment)
    navHost?.let { navFragment ->
        navFragment.childFragmentManager.primaryNavigationFragment?.let {fragment->
                //DO YOUR STUFF
        }
    }
}

Solution 4 - Android

This seems like the cleanest solution. Update: Changed extension function to property. Thanks Igor Wojda.

1. Create the following extension

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager

val FragmentManager.currentNavigationFragment: Fragment?
    get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()

2. In Activity with NavHostFragment use it like this:

val currentFragment = supportFragmentManager.currentNavigationFragment

Solution 5 - Android

Use addOnDestinationChangedListener in activity having NavHostFragment

For Java

 NavController navController= Navigation.findNavController(MainActivity.this,R.id.your_nav_host);

        navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
            @Override
            public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
                Log.e(TAG, "onDestinationChanged: "+destination.getLabel());
            }
        });

For Kotlin

var navController :NavController=Navigation.findNavController(this, R.id.nav_host_fragment)
    navController.addOnDestinationChangedListener { controller, destination, arguments ->
        Log.e(TAG, "onDestinationChanged: "+destination.label);

    }

Solution 6 - Android

this might be late but for anyone who's still looking

val currentFragment = NavHostFragment.findNavController(nav_host_fragment).currentDestination?.id

then you can do something like

if(currentFragment == R.id.myFragment){
     //do something
}

note that this is for kotlin, java code should be almost the same

Solution 7 - Android

First, you get the current fragment by id, then you can find the fragment, depending on that id.

int id = navController.getCurrentDestination().getId();
Fragment fragment = getSupportFragmentManager().findFragmentById(id);

Solution 8 - Android

My requirement is to get the current visible fragment from Parent activity,my solution is

 private LoginFragment getCurrentVisibleFragment() {
        NavHostFragment navHostFragment = (NavHostFragment)getSupportFragmentManager().getPrimaryNavigationFragment();
        FragmentManager fragmentManager = navHostFragment.getChildFragmentManager();
        Fragment loginFragment = fragmentManager.getPrimaryNavigationFragment();
        if(loginFragment instanceof LoginFragment){
            return (LoginFragment)loginFragment;
        }
        return null;
    }

This may help some one with same problem.

Solution 9 - Android

navController().currentDestination?.id

will give you your current Fragment's id where

private fun navController() = Navigation.findNavController(this, R.id.navHostFragment)

this id is the id which you have given in your Navigation Graph XML file under fragment tag. You could also compare currentDestination.label if you want.

Solution 10 - Android

Found working solution.

private fun getCurrentFragment(): Fragment? {
    val currentNavHost = supportFragmentManager.findFragmentById(R.id.nav_host_id)
    val currentFragmentClassName = ((this as NavHost).navController.currentDestination as FragmentNavigator.Destination).className
    return currentNavHost?.childFragmentManager?.fragments?.filterNotNull()?.find {
        it.javaClass.name == currentFragmentClassName
    }
}

Solution 11 - Android

Using navigation components, I got the current displayed fragment using this line of code:

val fragment = parentFragmentManager.primaryNavigationFragment

Solution 12 - Android

From an Activity that uses NavHostFragment, you can use the code below to retrieve the instance of the Active Fragment.

val fragmentInstance = myNavHostFragment?.childFragmentManager?.primaryNavigationFragment

Solution 13 - Android

As per @slhddn answer and comment this is how I'm using it and retrieving the fragment id from the nav_graph.xml file:

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    setSupportActionBar(findViewById(R.id.toolbar))

    val navController = findNavController(this, R.id.nav_host_fragment)

    ivSettingsCog.setOnClickListener {

        if (navController.currentDestination?.id == R.id.updatesFragment) // Id as per set up on nav_graph.xml file
        {
            navController.navigate(R.id.action_updatesFragment_to_settingsFragment)
        }

    }

}

}

Solution 14 - Android

Within your activity, hosting the NavHostFragment we can write the following piece of code to fetch the instance of the currently displayed fragment

Fragment fragment = myNavHostFragment.getChildFragmentManager().findFragmentById(R.id.navHostFragmentId)
if(fragment instanceOf MyFragment) {
  //Write your code here
}

Here R.id.navHostFragmentId is the resId for the NavHostFragment within your activity xml

Solution 15 - Android

Make :

• in some button in your fragment:

val navController = findNavController(this)
  navController.popBackStack()

• In your Activity onBackPressed()

override fun onBackPressed() {
        val navController = findNavController(R.id.nav_host_fragment)
        val id = navController.currentDestination?.getId()
        if (id == R.id.detailMovieFragment){
            navController.popBackStack()
            return
        }

        super.onBackPressed()
    } 

Solution 16 - Android

The first fragment in navhost fragment is the current fragment

Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment();
if (navHostFragment != null) 
{Fragment fragment = navHostFragment.getChildFragmentManager().getFragments().get(0);}

Solution 17 - Android

The best way I could figure out with 1 fragment, Kotlin, Navigation usage:

On your layout file add the tag: "android:tag="main_fragment_tag""

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

On your Activity:

val navHostFragment = supportFragmentManager.findFragmentByTag("main_fragment_tag") as NavHostFragment
val mainFragment = navHostFragment.childFragmentManager.fragments[0] as MainFragment
mainFragment.mainFragmentMethod()

Solution 18 - Android

Here is my solution for java

    NavHostFragment  navHostFragment= (NavHostFragment) getSupportFragmentManager().getFragments().get(0);
    MyFragment  fragment = (MyFragment) navHostFragment.getChildFragmentManager().getFragments().get(0);
    fragment.doSomething();

Solution 19 - Android

can you please check with getChildFragmentManager() call with

NavHostFragment fragment = supportFragmentManager.findFragmentById(R.id.nav_host);
MyFragment frag = (MyFragment) fragment.getChildFragmentManager().findFragmentByTag(tag);

Solution 20 - Android

If you need the instance of your fragment, you can go with:

(Activity) => supportFragmentManager.fragments.first().childFragmentManager.fragments.first()

It's very ugly but from there you can check if it's an instance of the fragment you want to play around with

Solution 21 - Android

On Androidx, I have tried many methods for finding out required fragment from NavHostFragment. Finally I could crack it with below method

public Fragment getFunctionalFragment (String tag_name)
{
    NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
    FragmentManager navHostManager = Objects.requireNonNull(navHostFragment).getChildFragmentManager();

    Fragment fragment=null;
    List fragment_list = navHostManager.getFragments();

    for (int i=0; i < fragment_list.size() ; i ++ )
    {
        if ( fragment_list.get(i) instanceof HomeFragment && tag_name.equals("frg_home")) {
            fragment = (HomeFragment) fragment_list.get(i);
            break;
        }
    }

    return fragment;
}

Solution 22 - Android

This code works from me

NavDestination current = NavHostFragment.findNavController(getSupportFragmentManager().getPrimaryNavigationFragment().getFragmentManager().getFragments().get(0)).getCurrentDestination();

switch (current.getId()) {
    case R.id.navigation_saved:
        // WRITE CODE
        break;
}

Solution 23 - Android

this might be late but may help someone later.

if you are using nested navigations you can get id like this in Kotlin

val nav = Navigation.findNavController(requireActivity(), R.id.fragment_nav_host).currentDestination

and this is one of fragments in fragment_nav_host.xml

<fragment
    android:id="@+id/sampleFragment"
    android:name="com.app.sample.SampleFragment"
    android:label="SampleFragment"
    tools:layout="@layout/fragment_sample" />

and you can check all you need like this

if (nav.id == R.id.sampleFragment || nav.label == "SampleFragment"){}

Solution 24 - Android

Finally the working solution for those of you who are still searching Actually it is very simple and you can achieve this using callback.

follow these steps:

  1. Create a listener inside the fragment you want to get the instance from activity onCreate()

    public class HomeFragment extends Fragment {
    
    private OnCreateFragment createLIstener;
    
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        createLIstener.onFragmentCreated(this);
        View root = inflater.inflate(R.layout.fragment_home, container, false);
        //findViews(root);
        return root;
    }
    
    @Override
    public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.menu_main, menu);
        
    }
    
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        if (item.getItemId()==R.id.action_show_filter){
            //do something
        }
        return super.onOptionsItemSelected(item);
    }
    
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            createLIstener = (OnCreateFragment) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString() + " must implement OnArticleSelectedListener");
            }
        }
    
        public interface OnCreateFragment{
            void onFragmentCreated(Fragment f);
        }
    }
    
  2. Implement your listener in the host Fragment/Activity

    public class MainActivity extends AppCompatActivity implements HomeFragment.OnCreateFragment {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            BottomNavigationView navView = findViewById(R.id.nav_view);
           // Passing each menu ID as a set of Ids because each
           // menu should be considered as top level destinations.
            AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                    R.id.navigation_home,
                    R. ----)
            .build();
            NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
            NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
            NavigationUI.setupWithNavController(navView, navController);
        }
    
        @Override
        public void onFragmentCreated(Fragment f) {
            if (f!=null){
                H.debug("fragment created listener: "+f.getId());
                f.setHasOptionsMenu(true);
            }else {
                H.debug("fragment created listener: NULL");
            }
        }
    }
    

And that is everything you need to do the job. Hop this help someone

Solution 25 - Android

val fragment: YourFragment? = yourNavHost.findFragment()

Note: findFragment extension function is located in androidx.fragment.app package, and it's generic function

Solution 26 - Android

create extension function on Fragment Manager

inline fun <reified T : Fragment> FragmentManager.findNavFragment(hostId: Int): T? {

    val navHostFragment = findFragmentById(hostId)

    return navHostFragment?.childFragmentManager?.fragments?.findLast {
        it is T
    } as T?
}

Now simply use it by giving id of the hosting fragment and get the specified fragment

    val myFragment: MyFragment? = supportFragmentManager.findNavFragment<MyFragment>(R.id.nav_host_id)

Solution 27 - Android

I combined Andrei Toaders answer and Mukul Bhardwajs answer with an OnBackStackChangedListener.

As an attribute:

private FooFragment fragment;

In my onCreate

NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host);
FragmentManager navHostManager = Objects.requireNonNull(navHostFragment).getChildFragmentManager();
FragmentManager.OnBackStackChangedListener listener = () -> {
        List<Fragment> frags = navHostManager.getFragments();
        if(!frags.isEmpty()) {
            fragment = (FooFragment) frags.get(0);
        }
};
navController.addOnDestinationChangedListener((controller, destination, arguments) -> {
        if(destination.getId()==R.id.FooFragment){
            navHostManager.addOnBackStackChangedListener(listener);
        } else {
            navHostManager.removeOnBackStackChangedListener(listener);
           fragment = null;
        }
});

This way i can get a fragment, which will be displayed later on. One even may be able to loop though frags and check multiple fragments with instanceof.

Solution 28 - Android

I need to do this to setup a bottom navigation view and I did it this way:

val navController = Navigation.findNavController(requireActivity(), R.id.nav_tabs_home)
        val bottomNavBar: BottomNavigationView = nav_content_view
        NavigationUI.setupWithNavController(bottomNavBar, navController)

Solution 29 - Android

The best way to achieve this is to register a fragment lifecycle callback.

As per the original question, if your NavHostFragment is defined as...

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

Then in your main activity onCreate(..)...

nav_host.childFragmentManager.registerFragmentLifecycleCallbacks(
    object:FragmentManager.FragmentLifecycleCallbacks() {
        override fun onFragmentViewCreated(
            fm: FragmentManager, f: Fragment, v: View,
            savedInstanceState: Bundle?
        ) {
            // callback method always called whenever a
            // fragment is added, or, a back-press returns
            // to the start-destination
        }
    }
)

Other callback methods may be overridden to fit your requirements.

Solution 30 - Android

This solution will work in most situations Try this:

val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment?.parentFragment as MainFragment

or this:

val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment as MainFragment

Solution 31 - Android

This works for me

(navController.currentDestination as FragmentNavigator.Destination).className 

It will return canonicalName of your fragment

Solution 32 - Android

In your activity define a fragment object. And from each fragment call this method by passing fragment object, like So the static fragment object will be overridden by current showing fragment every time.

//method in MainActivity
private static Fragment fragment;

public void setFragment(Fragment fragment){
this.fragment = fragment;
}

//And from your fragment class, you can call
((<yourActivity in which fragment present>)getActivity()).setFragment(<your fragment object>);

//if you want to set it directly;
 ((<yourActivity in which fragment present>)getActivity()).fragment=<your fragment object>;

You can also set callback from fragment to activity, for a better approach and pass your current fragment object.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlinView Question on Stackoverflow
Solution 1 - AndroidAndrei TView Answer on Stackoverflow
Solution 2 - AndroidslhddnView Answer on Stackoverflow
Solution 3 - AndroidNicolas PietriView Answer on Stackoverflow
Solution 4 - AndroidAleksandar IlicView Answer on Stackoverflow
Solution 5 - AndroidMukul BhardwajView Answer on Stackoverflow
Solution 6 - AndroidMoTahirView Answer on Stackoverflow
Solution 7 - AndroidAbu-BakrView Answer on Stackoverflow
Solution 8 - AndroidCLIFFORD P YView Answer on Stackoverflow
Solution 9 - AndroidAbhishek BansalView Answer on Stackoverflow
Solution 10 - AndroidTomas KuhnView Answer on Stackoverflow
Solution 11 - AndroidJazib KhanView Answer on Stackoverflow
Solution 12 - AndroidjjzView Answer on Stackoverflow
Solution 13 - AndroidFrancislainy CamposView Answer on Stackoverflow
Solution 14 - AndroidMaximusView Answer on Stackoverflow
Solution 15 - AndroidPaulo Linhares - PackappsView Answer on Stackoverflow
Solution 16 - AndroidEren TüfekçiView Answer on Stackoverflow
Solution 17 - Androidpatel dhruvalView Answer on Stackoverflow
Solution 18 - AndroidLuis MuñozView Answer on Stackoverflow
Solution 19 - AndroidShiam Shabbir HimelView Answer on Stackoverflow
Solution 20 - AndroidAilelameView Answer on Stackoverflow
Solution 21 - AndroidKarthikView Answer on Stackoverflow
Solution 22 - AndroidFaisal ShaikhView Answer on Stackoverflow
Solution 23 - AndroidPayam MonsefView Answer on Stackoverflow
Solution 24 - AndroidEcclesiaste PandaView Answer on Stackoverflow
Solution 25 - AndroidNarek HayrapetyanView Answer on Stackoverflow
Solution 26 - AndroidJalees MukarramView Answer on Stackoverflow
Solution 27 - AndroidXerusialView Answer on Stackoverflow
Solution 28 - AndroidRoque RuedaView Answer on Stackoverflow
Solution 29 - AndroidmigueltView Answer on Stackoverflow
Solution 30 - Androiduser2288580View Answer on Stackoverflow
Solution 31 - AndroidIncView Answer on Stackoverflow
Solution 32 - AndroidRanjanView Answer on Stackoverflow