How do I get the currently displayed fragment?

2018-12-31 16:48发布

问题:

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?

回答1:

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)getFragmentManager().findFragmentByTag(\"MY_FRAGMENT\");
if (myFragment != null && myFragment.isVisible()) {
   // add your code here
}

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



回答2:

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. Hope it helps someone else too.



回答3:

Here is my solution which I find handy for low fragment scenarios

public Fragment getVisibleFragment(){
    FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
    List<Fragment> fragments = fragmentManager.getFragments();
    if(fragments != null){
        for(Fragment fragment : fragments){
            if(fragment != null && fragment.isVisible())
                return fragment;
        }
    }
    return null;
}


回答4:

Every time when you show fragment you must put it tag into backstack:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_ENTER_MASK);       
ft.add(R.id.primaryLayout, fragment, tag);
ft.addToBackStack(tag);
ft.commit();        

And then when you need to get current fragment you may use this method:

public BaseFragment getActiveFragment() {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        return null;
    }
    String tag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
    return (BaseFragment) getSupportFragmentManager().findFragmentByTag(tag);
}


回答5:

What I am using to find current displaying fragment is in below code. It is simple and it works for me by now. It runs in the activity which holds the fragments

    FragmentManager fragManager = this.getSupportFragmentManager();
    int count = this.getSupportFragmentManager().getBackStackEntryCount();
    Fragment frag = fragManager.getFragments().get(count>0?count-1:count);


回答6:

The reactive way:

Observable.from(getSupportFragmentManager().getFragments())
    .filter(fragment -> fragment.isVisible())
    .subscribe(fragment1 -> {
        // Do something with it
    }, throwable1 -> {
        // 
    });


回答7:

My method is based on try / catch like this :

MyFragment viewer = null;
try {
    viewer = (MyFragment) getFragmentManager().findFragmentByTag(MY_TAG_FRAGMENT);
} catch (ClassCastException e) {
    // not that fragment
}

But there may be a better way ...



回答8:

It\'s a bit late, But for anyone who is interested : If you know the index of the your desired fragment in FragmentManager just get a reference to it and check for isMenuVisible() function! here :

getSupportFragmentManager().getFragments().get(0).isMenuVisible()

If true Its visible to user and so on!



回答9:

Well, this question got lots of views and attention but still did not contained the easiest solution from my end - to use getFragments().

            List fragments = getSupportFragmentManager().getFragments();
            mCurrentFragment = fragments.get(fragments.size() - 1);


回答10:

1)

ft.replace(R.id.content_frame, fragment, **tag**).commit();

2)

FragmentManager fragmentManager = getSupportFragmentManager();
Fragment currentFragment = fragmentManager.findFragmentById(R.id.content_frame);

3)

if (currentFragment.getTag().equals(**\"Fragment_Main\"**))
{
 //Do something
}
else
if (currentFragment.getTag().equals(**\"Fragment_DM\"**))
{
//Do something
}


回答11:

Inspired by Tainy\'s answer, here is my two cents. Little modified from most other implementations.

private Fragment getCurrentFragment() {
    FragmentManager fragmentManager = myActivity.getSupportFragmentManager();
    int stackCount = fragmentManager.getBackStackEntryCount();
    if( fragmentManager.getFragments() != null ) return fragmentManager.getFragments().get( stackCount > 0 ? stackCount-1 : stackCount );
    else return null;
}

Replace \"myActivity\" with \"this\" if it is your current activity or use reference to your activity.



回答12:

There\'s a method called findFragmentById() in SupportFragmentManager. I use it in the activity container like :

public Fragment currentFragment(){
    return getSupportFragmentManager().findFragmentById(R.id.activity_newsfeed_frame);
}

That\'s how to get your current Fragment. If you have custom Fragment and need to check what Fragment it is, I normally use instanceof :

if (currentFragment() instanceof MyFrag){
    // Do something here
}


回答13:

This is simple way to get current fragment..

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
  @Override public void onBackStackChanged() {
    currentFragment = fragmentManager.findFragmentById(R.id.content);
    if (currentFragment !=  null && (currentFragment instanceof LoginScreenFragment)) {
      logout.setVisibility(View.GONE);
    } else {
      logout.setVisibility(View.VISIBLE);
    }
  }
});


回答14:

Sev\'s answer works for when you hit the back button or otherwise change the backstack.

I did something slightly different, though. I have a backstack change listener setup on a base Fragment and its derived fragments and this code is in the listener:

Fragment f = getActivity().getSupportFragmentManager().findFragmentById(R.id.container);

if (f.getClass().equals(getClass())) {
    // On back button, or popBackStack(),
    // the fragment that\'s becoming visible executes here,
    // but not the one being popped, or others on the back stack

    // So, for my case, I can change action bar bg color per fragment
}


回答15:

You can query which fragment is loaded into your Activities content frame, and retrieve the fragment class, or fragment \'simple name\' (as a string).

public String getCurrentFragment(){
     return activity.getSupportFragmentManager().findFragmentById(R.id.content_frame).getClass().getSimpleName();
}

Usage:

Log.d(TAG, getCurrentFragment());

Outputs:

D/MainActivity: FragOne


回答16:

This is work for me. I hope this will hepl someone.

FragmentManager fragmentManager = this.getSupportFragmentManager();  
        String tag = fragmentManager
                    .getBackStackEntryAt(
                    fragmentManager
                    .getBackStackEntryCount() - 1)
                    .getName();
              Log.d(\"This is your Top Fragment name: \", \"\"+tag);


回答17:

If you are getting the current instance of Fragment from the parent activity you can just

findFragmentByID(R.id.container);

This actually get\'s the current instance of fragment that\'s populated on the view. I had the same issue. I had to load the same fragment twice keeping one on backstack.

The following method doesn\'t work. It just gets a Fragment that has the tag. Don\'t waste your time on this method. I am sure it has it\'s uses but to get the most recent version of the same Fragment is not one of them.

findFragmentByTag()


回答18:

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\");
}


回答19:

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\");
        }


回答20:

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 method is not called when a fragment is popped off the backstack, 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 which is triggered in the main activity when a fragment becomes visible inside the activity.



回答21:

I ran into a similar problem, where I wanted to know what fragment was last displayed when the back key was pressed. I used a very simple solution that worked for me. Each time I open a fragment, in the onCreate() method, I set a variable in my singleton (replace \"myFragment\" with the name of your fragment)

MySingleton.currentFragment = myFragment.class;

The variable is declared in the singleton as

public static Class currentFragment = null; 

Then in the onBackPressed() I check

    if (MySingleton.currentFragment == myFragment.class){
        // do something
        return;
    }
    super.onBackPressed();

Make sure to call the super.onBackPressed(); after the \"return\", otherwise the app will process the back key, which in my case caused the app to terminate.



回答22:

In case of scrolled fragments, when your use instance of ViewPager class, suppose mVeiwPager, you can call mViewPager.getCurrentItem() for get current fragment int number.

in MainLayout.xml

<?xml version=\"1.0\" encoding=\"utf-8\"?>
<android.support.design.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"
    xmlns:app=\"http://schemas.android.com/apk/res-auto\"
    xmlns:tools=\"http://schemas.android.com/tools\"
    android:layout_width=\"match_parent\"
    android:layout_height=\"match_parent\"
    android:fitsSystemWindows=\"true\"
    android:orientation=\"vertical\"
    tools:context=\"unidesign.photo360.MainActivity\">

    <android.support.design.widget.AppBarLayout
        android:id=\"@+id/appbar\"
        android:layout_width=\"match_parent\"
        android:layout_height=\"wrap_content\"
        android:fitsSystemWindows=\"false\"
        android:theme=\"@style/AppTheme.AppBarOverlay\"
        app:expanded=\"false\">

        <android.support.v7.widget.Toolbar
            android:id=\"@+id/main_activity_toolbar\"
            android:layout_width=\"match_parent\"
            android:layout_height=\"wrap_content\"
            android:layout_weight=\"1\"
            app:popupTheme=\"@style/AppTheme.PopupOverlay\"
            app:title=\"@string/app_name\">

        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>


    <android.support.v4.view.ViewPager
        android:id=\"@+id/view_pager\"
        android:layout_width=\"match_parent\"
        android:layout_height=\"wrap_content\">

    </android.support.v4.view.ViewPager>
    
</android.support.design.widget.CoordinatorLayout>

in MainActivity.kt

class MainActivity : AppCompatActivity() {
    
        lateinit var mViewPager: ViewPager
        lateinit var pageAdapter: PageAdapter
        
//      ...
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            
            pageAdapter = PageAdapter(supportFragmentManager)
            mViewPager = findViewById(R.id.view_pager)
//          ...
            }
            
        override fun onResume() {
          super.onResume()
          var currentFragment = pageAdapter.getItem(mViewPager.currentItem)
//         ...
          }



回答23:

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
    }
}


回答24:

Maybe the simplest way is:

public MyFragment getVisibleFragment(){
    FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
    List<Fragment> fragments = fragmentManager.getFragments();
    for(Fragment fragment : fragments){
        if(fragment != null && fragment.getUserVisibleHint())
            return (MyFragment)fragment;
    }
    return null;
}

It worked for me



回答25:

Using an event bus (like Otto, EventBus or an RxJava Bus) is especially handy in these situations.

While this approach doesn\'t necessarily hand you down the currently visible fragment as an object (though that too can be done but it leads to a longer call chain), it allows you execute actions on the currently visible fragment (which is usually what you want to do knowing the currently visible fragment).

  1. make sure you respect the fragment lifecycle and register/unregister the event bus at the appropriate times
  2. at the point where you need to know the currently visible fragment and execute a set of actions. shoot an event out with the event bus.

all visible fragments that have registered with the bus will execute the necessary action.



回答26:

A bit strange but I looked at FragmentManager$FragmentManagerImpl and the following works for me:

public static Fragment getActiveFragment(Activity activity, int index)
{
    Bundle bundle = new Bundle();
    String key = \"i\";
    bundle.putInt(key,index);
    Fragment fragment=null;
    try
    {
        fragment = activity.getFragmentManager().getFragment(bundle, key);
    } catch(Exception e){}
    return fragment;
}

to get the first active fragment use 0 as the index



回答27:

public Fragment getVisibleFragment() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    List<Fragment> fragments = fragmentManager.getFragments();
    if(fragments != null) {
        for (Fragment fragment : fragments) {
            if (fragment != null && fragment.isVisible())
                return fragment;
        }
    }
    return null;
}

This works for me. You need to perform a null check before you iterate through the fragments list. There could be a scenario that no fragments are loaded on the stack.

The returning fragment can be compared with the fragment you want to put on the stack.



回答28:

Please try this method .....

private Fragment getCurrentFragment(){
    FragmentManager fragmentManager = getSupportFragmentManager();
    String fragmentTag = fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1).getName();
    Fragment currentFragment = getSupportFragmentManager()
.findFragmentByTag(fragmentTag);
    return currentFragment;
}


回答29:

You can get current fragment by using following code

FragmentClass f = (FragmentClass)viewPager.getAdapter().instantiateItem(viewPager, viewPager.getCurrentItem());


回答30:

You can add a class variable selectedFragment, and every time you change the fragment you update the variable.

public Fragment selectedFragment;
public void changeFragment(Fragment newFragment){
    FragmentManager fragMgr = getSupportFragmentManager();
    FragmentTransaction fragTrans = fragMgr.beginTransaction();
    fragTrans.replace(android.R.id.content, newFragment);
    fragTrans.addToBackStack(null);
    fragTrans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    fragTrans.commit();
    //here you update the variable
    selectedFragment = newFragment;
}

then you can use selectedFragment wherever you want