有没有一种方法可以从堆栈的顶部获取fragment?

45

我在MainActivity中有一个ListFragment。以下是我如何设置我的fragment对象。

FragmentManager fragmentManager = activity.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment newFragment = new MyFragment();
fragmentTransaction.replace(R.id.framecontainer, newFragment, "tag");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

当用户按下返回按钮时,我至少需要调用操作栏和菜单来进行更改。
getActionBar().setTitle(title);
getActionBar().setDisplayHomeAsUpEnabled(isEnabled);
invalidateOptionsMenu();

我需要知道当前显示的是哪种片段,这样我才能知道如何设置操作栏。我将设置选项存储在片段中作为参数。

String title = fragment.getArguments().getString("KEY_TITLE");
boolean isEnabled = fragment.getArguments().getBoolean("KEY_ISENABLED");

我搜索了相关问题,发现可以通过调用代码片段来获取该片段。
MyFragment fragment = (MyFragment) getSupportFragmentManager()
        .findFragmentByTag("tag");

然而,我必须将所有标签存储在自定义堆栈中,并在用户按下后退按钮时每次调用 onBackPressed() 中的 pop()

因此,我的问题是,是否有一种方法可以直接从堆栈中获取当前可见的片段?

注意:请记住,片段类型不同,不仅仅是 MyFragment。

5个回答

72

类似这样的东西应该能帮助你在后退时解决活动问题:

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

@Override
public void onBackPressed() {
    Fragment fragmentBeforeBackPress = getCurrentFragment();
    // Perform the usual back action
    super.onBackPressed();
    Fragment fragmentAfterBackPress = getCurrentFragment();
}

希望这有所帮助。

10
如果按照你的方式进行操作,似乎我还需要设置**fragmentTransaction.addToBackStack(tag);否则,我将遇到NullPointerException。因此fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount() - 1).getName();**并不指代标签名称。 - Dragon warrior
1
是的...你需要检查空值和错误的数学计算((getBackStackEntryCount-1) > 0等等)。我有点写得太快了。此外,没有标签添加的片段将显示为空。 - petey
@umerk44 在你的 getCurrentFragment 实现中,你必须考虑到空的回退栈名称。我更喜欢使用字符串名称来避免 instanceof 类型检测,并且在调试时最有帮助--通过进行回退栈遍历/循环并打印名称。 - petey
我认为您混淆了片段标记名称(用于添加或替换片段)和返回栈名称(仅可用于使用该名称弹出片段)。我想知道上述内容是否有效。 - eC Droid
这是非常好的答案!谢谢。 - Faizan Mubasher

35
FragmentManager.findFragmentById(fragmentsContainerId) 

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

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

编辑:现在在2018年FragmentManager中有getFragments方法,它返回List<Fragment>。从文档中可以看出: 列表中片段的顺序是它们添加或附加的顺序。因此,我们似乎可以直接从该列表中取出最后一个片段:

     List<Fragment> list = fragmentManager.getFragments();
     //get last one 
     Fragment topFragment = list.get(list.size() - 1);

1
这似乎有点奇怪...但对我来说确实非常有效 :). 文档确实说它搜索后退栈,所以希望它在所有版本的Android中始终从堆栈顶部开始搜索(手指交叉)。 - delrocco
我已经寻找这个很长时间了,感谢您澄清了这个监听器的工作方式。 - mikebertiean
getFragments 对我有用!我建议您将其放在评论顶部以获得更多的关注 :) - JonZarate

3

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

Kotlin:

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

Java:

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

1

已经有一个被标记为正确的答案了,我的额外信息与之不太不同。但是,当我使用接收器并尝试确定接收器所在的片段是否是堆栈上当前顶部的片段时,我遇到了麻烦。您可能会遇到许多NPE和索引越界的问题。因此,我写了这个,希望能帮助某些人。

private boolean isFragmentOnTop(Activity parentActivity, final String fragmentName){
        FragmentManager fmManager = parentActivity.getFragmentManager();
        if(fmManager.getBackStackEntryCount() == 0){
            LOG.i("BackStack entry count is 0: " + this);
            return false;
        }
        String fragmentNameOnStackTop = "";
        final FragmentManager.BackStackEntry topEntry = fmManager.getBackStackEntryAt(fmManager.getBackStackEntryCount() -1);
        if(topEntry != null) {
            fragmentNameOnStackTop = topEntry.getName();
        }
        LOG.d("Got fragments name: " + fragmentNameOnStackTop);
        return fragmentNameOnStackTop != null ? fragmentNameOnStackTop.equals(fragmentName) : false;
    }

请注意,这对于具有一些片段的活动有效。如果您正在使用ViewPager和childfragmentmanager,请注意。
而且,请不要忘记在FragmentTransaction.addToBackStack(fragmentName)中设置fragmentName。

1
这个帮助方法从栈顶获取片段:
public Fragment getTopFragment() {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        return null;
    }
    String fragmentTag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
    return getSupportFragmentManager().findFragmentByTag(fragmentTag);
}

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