Leem.fin
Leem.fin

Reputation: 42602

How do I get the currently displayed fragment?

I am playing with fragments in Android.

I know I can change a fragment by using the following code:

FragmentManager fragMgr = getSupportFragmentManager();
FragmentTransaction fragTrans = fragMgr.beginTransaction();

MyFragment myFragment = new MyFragment(); //my custom fragment

fragTrans.replace(android.R.id.content, myFragment);
fragTrans.addToBackStack(null);
fragTrans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragTrans.commit();

My question is, in a Java file, how can I get the currently displayed Fragment instance?

Upvotes: 544

Views: 614207

Answers (30)

kmarin
kmarin

Reputation: 342

final FragmentManager fm = this.getSupportFragmentManager();
final Fragment fragment = fm.findFragmentByTag("MY_FRAGMENT");

if(fragment != null && fragment.isVisible()) {
    Log.i("TAG","my fragment is visible");
} else {
    Log.i("TAG","my fragment is not visible");
}

Upvotes: 4

Cory Roy
Cory Roy

Reputation: 5609

To return current Fragment destination and you are using the AndroidX Navigation:

val currentFragment = findNavController(R.id.your_navhost)?.currentDestination

To return current Fragment name, you can use the following instead:

val currentFragment = supportFragmentManager.findFragmentById(R.id. your_navhost)?.childFragmentManager?.primaryNavigationFragment

For more info on this navigation component: https://developer.android.com/guide/navigation/navigation-getting-started

Upvotes: 15

androholic
androholic

Reputation: 696

This is a simple solution I have Found. It will show all the fragment managed by navGraph

navHostFragment =
                supportFragmentManager.findFragmentById(R.id.nav_host_fragment_content_main) as NavHostFragment
            navController = navHostFragment.navController
    
            navGraph = navController.navInflater.inflate(R.navigation.nav_graph)
    
            val navView: BottomNavigationView = binding.navView
            navView.setupWithNavController(navController)
    
    
            navController.addOnDestinationChangedListener { controller, destination, arguments ->
                Log.e("HelloFragment", navController.currentDestination?.label.toString())
    
            }

Upvotes: 0

You must use a recursive function to find the current fragment because the fragment itself may have child fragments.

private fun findLastFragment(fragment: Fragment?): Fragment? {
    val mFragment = fragment?.childFragmentManager?.fragments?.lastOrNull()
    return if (mFragment == null) {
        fragment
    } else {
        findLastFragment(mFragment)
    }
}

for use the above function for example call

findLastFragment(activity.supportFragmentManager.fragments.lastOrNull())

Upvotes: 1

Sev
Sev

Reputation: 4908

I know it's an old post, but was having trouble with it previously too. Found a solution which was to do this in the onBackStackChanged() listening function

  @Override
    public void onBackPressed() {
        super.onBackPressed();

         Fragment f = getActivity().getFragmentManager().findFragmentById(R.id.fragment_container);
      if(f instanceof CustomFragmentClass) 
        // do something with f
        ((CustomFragmentClass) f).doSomething();

    }

This worked for me as I didn't want to iterate through every fragment I have to find one that is visible.

Upvotes: 457

i30mb1
i30mb1

Reputation: 4776

In androidx.fragment:fragment-ktx:1.4 there is a new way how can we get recently added fragment to the container. If you using FragmentContainerView as a container for yours fragments it will be easy:

val fragmentContainer: FragmentContainerView = ...
val currentFragment: Fragment = fragmentContainer.getFragment()

Upvotes: 2

sf_admin
sf_admin

Reputation: 577

I just needed to do this, if you have access to the nav controller, you can obtain the current fragment from the back stack easily:

// current fragments label/title:
navController.backStack.last.destination.label

// current fragments name:
navController.backStack.last.destination.displayName

To get access to nav controller (replace with correct name):

val navController = findNavController(R.id.nav_host_fragment_activity_main)

Upvotes: 1

Fedot Paranoic
Fedot Paranoic

Reputation: 1

Return the currently active primary navigation fragment for this FragmentManager.

public @Nullable Fragment getPrimaryNavigationFragment()      
Fragment fragment = fragmentManager.getPrimaryNavigationFragment();  
    

Upvotes: -1

Abanoub Hany
Abanoub Hany

Reputation: 656

In Your Activity init your fragment before on create

    MyFragment myFragment = new MyFragment(); // add this
 @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
........

then call the method to view your fragment

openFragment(this.myFragment);

Here is the method

(R.id.frame_container) is your fragment container id in xml file (Frame Layout)

 private void openFragment(final Fragment fragment)   {
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.frame_container, fragment);
        transaction.commit();

    }

then in your activity, the Override method should be like

    public void onBackPressed() {
            if (myFragment.isVisible()) {
                myFragment.onBackPressed(this);
                return;
            }
            super.onBackPressed();
        }

then inside your fragment put this method

public  void onBackPressed(Activity activity) {
    Toast.makeText(activity, "Back Pressed inside Fragment", Toast.LENGTH_SHORT).show();
}

Upvotes: 0

Anoop M Maddasseri
Anoop M Maddasseri

Reputation: 10549

This should work -

val visibleFragment = supportFragmentManager.fragments.findLast { fgm -> fgm.isVisible }
Timber.d("backStackIterator: visibleFragment: $visibleFragment")

Upvotes: 6

I had to do this very recently

public Fragment getCurrentFragment() {
     return fragmentManager.findFragmentById(R.id.container);
}

and finaly i got last fragment on this container.

Upvotes: 4

ufdeveloper
ufdeveloper

Reputation: 406

In the main activity, the onAttachFragment(Fragment fragment) method is called when a new fragment is attached to the activity. In this method, you can get the instance of the current fragment. However, the onAttachFragment(Fragment fragment) method is not called when a fragment is popped off the back stack, ie, when the back button is pressed to get the top fragment on top of the stack. I am still looking for a callback method that is triggered in the main activity when a fragment becomes visible inside the activity.

Upvotes: 1

ramdroid
ramdroid

Reputation: 6798

When you add the fragment in your transaction you should use a tag.

fragTrans.replace(android.R.id.content, myFragment, "MY_FRAGMENT");

...and later if you want to check if the fragment is visible:

MyFragment myFragment = (MyFragment)getSupportFragmentManager().findFragmentByTag("MY_FRAGMENT");
if (myFragment != null && myFragment.isVisible()) {
   // add your code here
}

See also http://developer.android.com/reference/android/app/Fragment.html

Upvotes: 512

Kotlin safer way than exposed here

supportFragmentManager.fragments.lastOrNull()?.let { currentFragment ->
               
      //Do something here
 }

Upvotes: 3

logeshpalani31
logeshpalani31

Reputation: 1620

  SupportFragmentManager.BeginTransaction().Replace(Resource.Id.patientFrameHome, test, "Test").CommitAllowingStateLoss();  

var fragment = SupportFragmentManager.FindFragmentByTag("Test") as V4Fragment;

  if (fragment == null && fragment.IsVisiable is true)
{
}

Upvotes: 2

coolcool1994
coolcool1994

Reputation: 3804

None of the above 30 answers fully worked for me. But here is the answer that worked:

Using Kotlin, when using Navigation Component:

fun currentVisibleFragment(): Fragment? {
    return supportFragmentManager.fragments.first()?.getChildFragmentManager()?.getFragments()?.get(0)
}

Upvotes: 6

IgorGanapolsky
IgorGanapolsky

Reputation: 26821

If you are using Jetpack Navigation library:

val currentFragment = defaultNavigator.currentDestination

Upvotes: 1

Biplob Das
Biplob Das

Reputation: 3104

Easy way to do that :

Fragment fr=getSupportFragmentManager().findFragmentById(R.id.fragment_container);
String fragmentName = fr.getClass().getSimpleName();

Upvotes: 4

Gk Mohammad Emon
Gk Mohammad Emon

Reputation: 6938

You can do it very easily also with a URL in logcat which will redirect you to the source code of current fragment source code. First, you need to add an OnBackStackChangedListener in host activity like -

activity.getChildFragmentManager().addOnBackStackChangedListener(backStackListener);

And the OnBackStackChangedListener implementation is -

    public FragmentManager.OnBackStackChangedListener backStackListener = () -> {

    String simpleName = "";
    String stackName = getStackTopName().trim();

    if (Validator.isValid(stackName) && stackName.length() > 0) {

      simpleName = stackName.substring(Objects.requireNonNull(stackName).lastIndexOf('.') + 1).trim();

      List<Fragment >
       fragmentList = getChildFragmentManager().getFragments();
      Fragment myCurrentFragment;

      for (int i = 0; i < fragmentList.size(); i++) {
       myCurrentFragment= fragmentList.get(i);
       if (myCurrentFragment.getClass().getSimpleName().equals(simpleName)) {
        //Now you get the current displaying fragment assigned in myCurrentFragment.
        break;
       }
       myFragment = null;
      }
     }


     //The code below is for the source code redirectable logcat which would be optional for you.
     StackTraceElement stackTraceElement = new StackTraceElement(simpleName, "", simpleName + ".java", 50);
     String fileName = stackTraceElement.getFileName();
     if (fileName == null) fileName = "";
     final String info = "Current Fragment is:" + "(" + fileName + ":" +
     stackTraceElement.getLineNumber() + ")";
     Log.d("now", info + "\n\n");
    };

And the getStackTopName() method is -

public String getStackTopName() {
    FragmentManager.BackStackEntry backEntry = null;
    FragmentManager fragmentManager = getChildFragmentManager();
    if (fragmentManager != null) {
        if (getChildFragmentManager().getBackStackEntryCount() > 0)
            backEntry = getChildFragmentManager().getBackStackEntryAt(
                    getChildFragmentManager().getBackStackEntryCount() - 1
            );
    }
    return backEntry != null ? backEntry.getName() : null;
}

Upvotes: 2

Saddan
Saddan

Reputation: 1655

it's so simple, not that much code you need to write yourFragment.isAdded() or yourFragment.isVisible();

I prefer isAdded(),both of them return boolean value use it in if condition and must initialize your fragment in onCreate() otherwise you will get null point exception.

Upvotes: 5

anamkin
anamkin

Reputation: 19

Here is a Kotlin solution:

if ( this.getSupportFragmentManager().getBackStackEntryCount()>0 ) {
    var fgmt = this.getSupportFragmentManager().fragments[this.getSupportFragmentManager().getBackStackEntryCount()-1]
    if( fgmt is FgmtClassName ) {
        (fgmt as FgmtClassName).doSth()
    }
}

Simplified way:

with ( this.getSupportFragmentManager() ) {
    if ( getBackStackEntryCount()>0 ) {
        var fgmt = fragments[getBackStackEntryCount()-1]
        if ( fgmt is FgmtClassName ) {
            (fgmt as FgmtClassName).doSth()
        }
    }
}

Upvotes: 1

Projit Roy
Projit Roy

Reputation: 19

if getFragmentManager() not works then try with getSupportFragmentManager() and add a tag at the time of load fragment.

public void onBackPressed(){

    Fragment fragment=getSupportFragmentManager().findFragmentByTag(/*enter your tag*/);


    if(fragment!=null && fragment.isVisible())
    {
        //do your code here
    }
    else
    {
       //do your code here
    }

}

Upvotes: 0

Abhishek
Abhishek

Reputation: 123

getSupportFragmentManager().findFragmentById(R.id.content_frame).getClass().getSimpleName();

Well, I guess this is the most straight forward answer to this question. I hope this helps.

Upvotes: 2

10101101
10101101

Reputation: 305

In case you have nested fragments, like viewpagers inside viewpagers etc and you want to get all nested fragments.

Thanks and courtesy of Matt Mombrea answer a little tweaked version.

private List<Fragment> getVisibleFragments(List<Fragment> searchFragments, List<Fragment> visibleFragments) {
    if (searchFragments != null && searchFragments.size() > 0) {
        for (Fragment fragment : searchFragments) {
            List<Fragment> nestedFragments = new ArrayList<>();
            List<Fragment> childFMFragments = fragment.getChildFragmentManager().getFragments();
            List<Fragment> fmFragments = fragment.getFragmentManager().getFragments();
            fmFragments.retainAll(childFMFragments);
            nestedFragments.addAll(childFMFragments);
            nestedFragments.addAll(fmFragments);
            getVisibleFragments(nestedFragments, visibleFragments);
            if (fragment != null && fragment.isVisible()) {
                visibleFragments.add(fragment);
            }
        }
    }
    return visibleFragments;
}

And here is the usage:

List<Fragment> allVisibleFragments = getVisibleFragments(searchFragments, visibleFragments);

For example:

List<Fragment> visibleFragments = new ArrayList<>();
List<Fragment> searchFragments = MainActivity.this.getSupportFragmentManager().getFragments();
Toast.makeText(this, ""+getVisibleFragments(searchFragments, visibleFragments), Toast.LENGTH_LONG).show();

Upvotes: 0

Mikel Pascual
Mikel Pascual

Reputation: 2211

I had to do this very recently and none of the answers here really suited this scenario.

If you are confident that only one fragment will be visible (full-screen), so really want to find what's at the top of the backstack. For instance, as a Kotlin for Fragment:

import androidx.fragment.app.Fragment

fun Fragment.setVisibilityChangeListener(clazz: Class<out Fragment>, listener: (Boolean) -> Unit) {
    fragmentManager?.run {
        addOnBackStackChangedListener {
            val topFragmentTag = getBackStackEntryAt(backStackEntryCount - 1).name
            val topFragment = findFragmentByTag(topFragmentTag)
            listener(topFragment != null && topFragment::class.java == clazz)
        }
    }
}

And use it like:

class MyFragment: Fragment {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        setVisibilityChangeListener(this::class.java) { visible -> 
            // Do stuff
        }
    }
}

Upvotes: 1

Thordax
Thordax

Reputation: 1733

My method is based on try / catch like this :

MyFragment viewer = null;
    if(getFragmentManager().findFragmentByTag(MY_TAG_FRAGMENT) instanceOf MyFragment){
    viewer = (MyFragment) getFragmentManager().findFragmentByTag(MY_TAG_FRAGMENT);
}

But there may be a better way ...

Upvotes: 13

Cafer Mert Ceyhan
Cafer Mert Ceyhan

Reputation: 1756

Kotlin way;

val currentFragment = supportFragmentManager.fragments.last()

Upvotes: 42

pableiros
pableiros

Reputation: 16032

If get here and you are using Kotlin:

var fragment = supportFragmentManager.findFragmentById(R.id.fragment_container)

R.id.fragment_container is the id where the fragment is presenting on their activity

Or if you want a nicer solution:

supportFragmentManager.findFragmentById(R.id.content_main)?.let {
    // the fragment exists

    if (it is FooFragment) {
        // The presented fragment is FooFragment type
    }
}

Upvotes: 9

Haroon khan
Haroon khan

Reputation: 1058

Checkout this solution. It worked for me to get the current Fragment.

if(getSupportFragmentManager().getBackStackEntryCount() > 0){
        android.support.v4.app.Fragment f = 
         getSupportFragmentManager().findFragmentById(R.id.fragment_container);
        if(f instanceof ProfileFragment){
            Log.d(TAG, "Profile Fragment");
        }else if(f instanceof SavedLocationsFragment){
            Log.d(TAG, "SavedLocations Fragment");
        }else if(f instanceof AddLocationFragment){
            Log.d(TAG, "Add Locations Fragment");
        }

Upvotes: 5

Jeffrey Chen
Jeffrey Chen

Reputation: 1967

I found findFragmentByTag isn't that convenient. If you have String currentFragmentTag in your Activity or parent Fragment, you need to save it in onSaveInstanceState and restore it in onCreate. Even if you do so, when the Activity recreated, onAttachFragment will called before onCreate, so you can't use currentFragmentTag in onAttachFragment(eg. update some views based on currentFragmentTag), because it's might not yet restored.

I use the following code:

Fragment getCurrentFragment() {
    List<Fragment> fragments = getSupportFragmentManager().getFragments();
    if(fragments.isEmpty()) {
        return null;
    }
    return fragments.get(fragments.size()-1);
}

The document of FragmentManager state that

The order of the fragments in the list is the order in which they were added or attached.

When you need to do stuff based on current fragment type, just use getCurrentFragment() instance of MyFragment instead of currentFragmentTag.equals("my_fragment_tag").

Note that getCurrentFragment() in onAttachFragment will not get the attaching Fragment, but the previous attached one.

Upvotes: 2

Related Questions