获取回退栈中最新的片段

117

如果我不知道片段的标签和ID,如何获取添加到返回堆栈中的最新片段实例?

FragmentManager fragManager = activity.getSupportFragmentManager();
FragmentTransaction fragTransacion = fragMgr.beginTransaction();

/****After add , replace fragments 
  (some of the fragments are add to backstack , some are not)***/

//HERE, How can I get the latest added fragment from backstack ??
17个回答

165
你可以使用API level 14引入的FragmentManager.BackStackEntry的getName()方法。该方法将返回添加到后退栈时所使用的标签,即你用addTobackStack(tag)添加Fragment时使用的标签。
int index = getActivity().getFragmentManager().getBackStackEntryCount() - 1
FragmentManager.BackStackEntry backEntry = getFragmentManager().getBackStackEntryAt(index);
String tag = backEntry.getName();
Fragment fragment = getFragmentManager().findFragmentByTag(tag);

你需要确保像这样将片段添加到后退栈中:

fragmentTransaction.addToBackStack(tag);

25
为了根据标签查找片段,必须使用相同的标签添加/替换它。可以使用FragmentTransaction.add(int containerViewId, Fragment fragment, String tag)或者FragmentTransaction.replace(int containerViewId, Fragment fragment, String tag)方法。更多信息请参考文档。 - Saqib
3
问题在于,如果你在后台堆栈中有一个片段出现两次,那么当你只有索引或后退堆栈实体时,就无法检索特定的片段。 - Justin
16
如果我无法通过“弹出”方法访问一个片段,那称它为“堆栈”的意义是什么? - Kenny Worden
5
RTFM: http://developer.android.com/reference/android/app/FragmentManager.BackStackEntry.html#getName()请仔细阅读文档:http://developer.android.com/reference/android/app/FragmentManager.BackStackEntry.html#getName() - artkoenig
1
我不知道为什么,但findFragmentByTag返回null,即使调试器明确显示标签是正确的。 - htafoya
显示剩余6条评论

48
FragmentManager.findFragmentById(fragmentsContainerId) 

function 函数返回后退栈中顶部 Fragment 的链接。使用示例:

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

2
这个答案在我的项目中很好用,因为我将除了根片段以外的每个片段都添加到了后退栈中。但是我猜如果最新添加的片段没有被添加到后退栈中,这个答案就不会起作用。 - Arne Evertsson

45

我个人尝试了许多解决方案,最终得出了这个可行的解决方案:

添加此实用方法,将在下面的多次使用中获取后退堆栈中片段的数量:

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

当您使用FragmentTransaction方法添加/替换片段时,请为您的片段生成一个唯一的标签(例如:通过使用堆栈中的片段数量):

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

最后,通过这种方法,您可以在后退栈中找到任何片段:

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

因此,获取后退栈中的顶部片段可以通过调用以下方法轻松实现:
protected Fragment getCurrentFragment() {
    return getFragmentAt(getFragmentCount() - 1);
}

希望这可以帮到你!

22

Kotlin

// In activities
activity.supportFragmentManager.fragments.lastOrNull()

// In fragments
fragment.childFragmentManager.fragments.lastOrNull()

8
如果fragments是空的,你可能需要使用.lastOrNull() - Westy92

14

这个帮助方法从堆栈顶部获取片段:

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

1
谢谢。最优雅的答案。在这里添加给 Kotlin 爱好者 https://dev59.com/M2kw5IYBdhLWcg3ws833#47336504 - Shirane85

6

在fragmentManager中有一个碎片列表。请注意,删除一个碎片不会使列表大小减小(该碎片条目只是变成null)。因此,一个有效的解决方案是:

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

2
不可靠。原因有三:1)这是片段管理器知道的所有片段列表,而不仅仅是堆栈上的片段。2)不能保证片段管理器将在列表末尾继续添加新片段。当然,在简单测试中它会这样做,但如果删除一个片段,留下一个空值,然后在某些情况下片段管理器决定重用该空槽呢?不是说它会这样做,但不能保证在任何情况下都不会这样做。3)如果您或一些未来的程序员开始使用attach/detach来管理片段,则这将无法匹配堆栈。 - ToolmakerSteve
嗨,谢谢你的解决方案,但它不够美观和简单。 - Muhammad Ali
我怀疑这不是一个可行的解决方案。getFragments() 返回一个缩短的片段集合。也许最后一个是可见的,但其他很多可能不可见。 - CoolMind

5

Deepak Goel提供的答案对我无效,因为我总是从entry.getName()得到null;

我的做法是这样设置片段标签的:

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

ft是我的fragment transaction,FRAGMENT_TAG是标签。然后我使用这段代码来获取fragment:

Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);

只有当您为所有片段提供相同的标记时,此方法才有效。但如果您想稍后找到特定的片段,这并不是一个好主意。 - Shirane85

5

我只是拿了@roghayeh hosseini(正确的)答案,并为那些在2017年的人将其转换成了Kotlin :)

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

*该方法应在Activity内部调用。

祝您愉快 :)


4

看起来有些改进了,因为下面的代码对我来说完美地运行了,但我在已经提供的答案中没有找到它。

Kotlin:

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

Java:

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

3
你可以使用 getBackStackEntryAt() 方法来获取后退栈中的条目。要知道活动在后退栈中保留了多少条目,可以使用 getBackStackEntryCount() 方法。
int lastFragmentCount = getBackStackEntryCount() - 1;

14
如何获取回退栈中的最后一个片段呢?popBackStackEntryAt() 方法只返回 BackStackEntry 实例,而不是片段。 - Leem.fin
1
获取最后一个片段:getBackStackEntryCount() - 1 - An-droid
但是,为了通过id(getId())获取该片段,您必须维护自己独立于Android后堆栈的堆栈。 - user153275
3
这个答案是错误的,我看到后退堆栈条目的id为0,因此无法通过id检索片段。 - Justin
2
这可能有点过时了,但对于任何漫游到这里的人来说:返回堆栈不保存片段,而是片段事务,这就是为什么这个答案是错误的。 - maciekjanusz
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接