get the latest fragment in backstack

纵饮孤独 提交于 2019-11-27 02:59:53
Deepak Goel

You can use the getName() method of FragmentManager.BackStackEntry which was introduced in API level 14. This method will return a tag which was the one you used when you added the Fragment to the backstack with addTobackStack(tag).

int index = getActivity().getFragmentManager().getBackStackEntryCount() - 1
FragmentManager.BackStackEntry backEntry = getFragmentManager().getBackStackEntryAt(index);
String tag = backEntry.getName();
Fragment fragment = getFragmentManager().findFragmentByTag(tag);

You need to make sure that you added the fragment to the backstack like this:

fragmentTransaction.addToBackStack(tag);
FragmentManager.findFragmentById(fragmentsContainerId) 

function returns link to top Fragment in backstack. Usage example:

    fragmentManager.addOnBackStackChangedListener(new OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            Fragment fr = fragmentManager.findFragmentById(R.id.fragmentsContainer);
            if(fr!=null){
                Log.e("fragment=", fr.getClass().getSimpleName());
            }
        }
    });

I personnaly tried many of those solutions and ended up with this working solution:

Add this utility method that will be used several times below to get the number of fragments in your backstack:

protected int getFragmentCount() {
    return getSupportFragmentManager().getBackStackEntryCount();
}

Then, when you add/replace your fragment using FragmentTransaction method, generate a unique tag to your fragment (e.g.: by using the number of fragments in your stack):

getSupportFragmentManager().beginTransaction().add(yourContainerId, yourFragment, Integer.toString(getFragmentCount()));

Finally, you can find any of your fragments in your backstack with this method:

private Fragment getFragmentAt(int index) {
    return getFragmentCount() > 0 ? getSupportFragmentManager().findFragmentByTag(Integer.toString(index)) : null;
}

Therefore, fetching the top fragment in your backstack can be easily achieved by calling:

protected Fragment getCurrentFragment() {
    return getFragmentAt(getFragmentCount() - 1);
}

Hope this helps!

There is a list of fragments in the fragmentMananger. Be aware that removing a fragment, does not make the list size decrease (the fragment entry just turn to null). Therefore, a valid solution would be:

public Fragment getTopFragment() {
 List<Fragment> fragentList = fragmentManager.getFragments();
 Fragment top = null;
  for (int i = fragentList.size() -1; i>=0 ; i--) {
   top = (Fragment) fragentList.get(i);
     if (top != null) {
       return top;
     }
   }
 return top;
}
roghayeh hosseini

this helper method get fragment from top of stack:

public Fragment getTopFragment() {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        return null;
    }
    String fragmentTag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
    return getSupportFragmentManager().findFragmentByTag(fragmentTag);
}
Eduardo

The answer given by deepak goel does not work for me because I always get null from entry.getName();

What I do is to set a Tag to the fragment this way:

ft.add(R.id.fragment_container, fragmentIn, FRAGMENT_TAG);

Where ft is my fragment transaction and FRAGMENT_TAG is the tag. Then I use this code to get the fragment:

Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);
Blackbelt

you can use getBackStackEntryAt(). In order to know how many entry the activity holds in the backstack you can use getBackStackEntryCount()

int lastFragmentCount = getBackStackEntryCount() - 1;

Kotlin

activity.supportFragmentManager.fragments.last()

Keep your own back stack: myBackStack. As you Add a fragment to the FragmentManager, also add it to myBackStack. In onBackStackChanged() pop from myBackStack when its length is greater than getBackStackEntryCount.

Just took @roghayeh hosseini (correct) answer and made it in Kotlin for those here in 2017 :)

fun getTopFragment(): Fragment? {
    supportFragmentManager.run {
        return when (backStackEntryCount) {
            0 -> null
            else -> findFragmentByTag(getBackStackEntryAt(backStackEntryCount - 1).name)
        }
    }
}

*This should be called from inside an Activity.

Enjoy :)

Looks like something has changed for the better, because code below works perfectly for me, but I didn't find it in already provided answers.

Kotlin:

supportFragmentManager.fragments[supportFragmentManager.fragments.size - 1]

Java:

getSupportFragmentManager().getFragments()
.get(getSupportFragmentManager().getFragments().size() - 1)

Actually there's no latest fragment added to the stack because you can add several or fragments to the stack in a single transaction or just remove fragments without adding a new one.

If you really want to have a stack of fragments and to be able to access a fragment by its index in the stack, you'd better have an abstraction layer over the FragmentManager and its backstack. Here's how you can do it:

public class FragmentStackManager {
  private final FragmentManager fragmentManager;
  private final int containerId;

  private final List<Fragment> fragments = new ArrayList<>();

  public FragmentStackManager(final FragmentManager fragmentManager,
      final int containerId) {
    this.fragmentManager = fragmentManager;
    this.containerId = containerId;
  }

  public Parcelable saveState() {
    final Bundle state = new Bundle(fragments.size());
    for (int i = 0, count = fragments.size(); i < count; ++i) {
      fragmentManager.putFragment(state, Integer.toString(i), fragments.get(i));
    }
    return state;
  }

  public void restoreState(final Parcelable state) {
    if (state instanceof Bundle) {
      final Bundle bundle = (Bundle) state;
      int index = 0;
      while (true) {
        final Fragment fragment =
            fragmentManager.getFragment(bundle, Integer.toString(index));
        if (fragment == null) {
          break;
        }

        fragments.add(fragment);
        index += 1;
      }
    }
  }

  public void replace(final Fragment fragment) {
    fragmentManager.popBackStackImmediate(
        null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    fragmentManager.beginTransaction()
        .replace(containerId, fragment)
        .addToBackStack(null)
        .commit();
    fragmentManager.executePendingTransactions();

    fragments.clear();
    fragments.add(fragment);
  }

  public void push(final Fragment fragment) {
    fragmentManager
        .beginTransaction()
        .replace(containerId, fragment)
        .addToBackStack(null)
        .commit();
    fragmentManager.executePendingTransactions();

    fragments.add(fragment);
  }

  public boolean pop() {
    if (isEmpty()) {
      return false;
    }

    fragmentManager.popBackStackImmediate();

    fragments.remove(fragments.size() - 1);
    return true;
  }

  public boolean isEmpty() {
    return fragments.isEmpty();
  }

  public int size() {
    return fragments.size();
  }

  public Fragment getFragment(final int index) {
    return fragments.get(index);
  }
}

Now instead of adding and removing fragments by calling FragmentManager directly, you should use push(), replace(), and pop() methods of FragmentStackManager. And you will be able to access the topmost fragment by just calling stack.get(stack.size() - 1).

But if you like hacks, I have to other ways of doing similar things. The only thing I have to mention is that these hacks will work only with support fragments.

The first hack is just to get all active fragments added to the fragment manager. If you just replace fragments one by one and pop the from the stack this method will return the topmost fragment:

public class BackStackHelper {
  public static List<Fragment> getTopFragments(
      final FragmentManager fragmentManager) {
    final List<Fragment> fragments = fragmentManager.getFragments();
    final List<Fragment> topFragments = new ArrayList<>();

    for (final Fragment fragment : fragments) {
      if (fragment != null && fragment.isResumed()) {
        topFragments.add(fragment);
      }
    }

    return topFragments;
  }
}

The second approach is event more hacky and allows you to get all fragments added in the last transaction for which addToBackStack has been called:

package android.support.v4.app;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class BackStackHelper {
  public static List<Fragment> getTopFragments(
      final FragmentManager fragmentManager) {
    if (fragmentManager.getBackStackEntryCount() == 0) {
      return Collections.emptyList();
    }

    final List<Fragment> fragments = new ArrayList<>();

    final int count = fragmentManager.getBackStackEntryCount();
    final BackStackRecord record =
        (BackStackRecord) fragmentManager.getBackStackEntryAt(count - 1);
    BackStackRecord.Op op = record.mHead;
    while (op != null) {
      switch (op.cmd) {
        case BackStackRecord.OP_ADD:
        case BackStackRecord.OP_REPLACE:
        case BackStackRecord.OP_SHOW:
        case BackStackRecord.OP_ATTACH:
          fragments.add(op.fragment);
      }
      op = op.next;
    }

    return fragments;
  }
}

Please notice that in this case you have to put this class into android.support.v4.app package.

Or you may just add a tag when adding fragments corresponding to their content and use simple static String field (also you may save it in activity instance bundle in onSaveInstanceState(Bundle) method) to hold last added fragment tag and get this fragment byTag() at any time you need...

The highest (Deepak Goel) answer didn't work well for me. Somehow the tag wasn't added properly.

I ended up just sending the ID of the fragment through the flow (using intents) and retrieving it directly from fragment manager.

If you use addToBackStack(), you can use following code.

List<Fragment> fragments = fragmentManager.getFragments(); activeFragment = fragments.get(fragments.size() - 1);

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!