113

如何获取添加到 backstack 中的最新片段实例(如果我不知道片段标签和 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 ??
4

17 回答 17

161

您可以使用在 API 级别 14 中引入的getName()方法FragmentManager.BackStackEntry。该方法将返回一个标签,该标签是您在将 Fragment 添加到 backstack 时使用的标签addTobackStack(tag)

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

您需要确保将片段添加到后台堆栈,如下所示:

fragmentTransaction.addToBackStack(tag);
于 2012-03-20T13:38:02.167 回答
49
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=", fr.getClass().getSimpleName());
            }
        }
    });
于 2014-04-05T13:13:41.423 回答
43

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

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

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

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

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

最后,您可以使用以下方法在 backstack 中找到任何片段:

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

因此,通过调用以下方法可以轻松地获取 backstack 中的顶部片段:

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

希望这可以帮助!

于 2015-01-20T13:20:29.170 回答
18

科特林

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

// In fragments
fragment.childFragmentManager.fragments.lastOrNull()
于 2019-05-28T20:03:36.280 回答
12

这个辅助方法从栈顶获取片段:

public Fragment getTopFragment() {
    if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
        return null;
    }
    String fragmentTag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
    return getSupportFragmentManager().findFragmentByTag(fragmentTag);
}
于 2017-10-17T07:17:04.773 回答
6

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

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;
}
于 2016-01-17T19:10:34.920 回答
5

deepak goel 给出的答案对我不起作用,因为我总是从中得到 null entry.getName()

我所做的是以这种方式为片段设置标签:

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

其中 ft 是我的片段交易并且FRAGMENT_TAG是标签。然后我使用这段代码来获取片段:

Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);
于 2012-10-30T16:40:34.550 回答
5

刚刚接受了@roghayeh hosseini(正确)的答案,并在 Kotlin 中为 2017 年的人制作了它:)

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

*这应该从 Activity 内部调用。

享受 :)

于 2017-11-16T18:12:50.317 回答
4

看起来有些事情已经变得更好了,因为下面的代码对我来说非常完美,但我在已经提供的答案中没有找到它。

科特林:

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

爪哇:

getSupportFragmentManager().getFragments()
.get(getSupportFragmentManager().getFragments().size() - 1)
于 2018-11-10T16:17:08.913 回答
3

您可以使用getBackStackEntryAt()。为了知道活动在后台堆栈中有多少条目,您可以使用getBackStackEntryCount()

int lastFragmentCount = getBackStackEntryCount() - 1;
于 2012-03-14T12:50:42.990 回答
3

我将在Deepak Goel 的回答中添加一些内容,因为包括我在内的很多人都使用他的方法得到了一个空值。显然,当您将片段添加到后台堆栈时,要使标签工作,您应该这样做:

getSupportFragmentManager.beginTransaction().replace(R.id.container_id,FragmentName,TAG_NAME).addToBackStack(TAG_NAME).commit();

您需要添加两次相同的标签。

我会发表评论,但我没有 50 名声望。

于 2020-03-11T09:56:10.243 回答
2

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.

于 2014-08-15T08:31:14.473 回答
2

如果您使用addToBackStack(),则可以使用以下代码。

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

于 2019-08-01T12:58:20.990 回答
1

实际上,堆栈中没有添加最新的片段,因为您可以在单个事务中向堆栈添加多个或片段,或者只是删除片段而不添加新片段。

如果你真的想拥有一堆片段并且能够通过它在堆栈中的索引来访问一个片段,那么你最好在它的堆栈FragmentManager和它的backstack之上有一个抽象层。以下是您的操作方法:

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

FragmentManager现在,您应该使用 、 和 的方法,而不是直接push()调用replace()pop()添加和删除片段FragmentStackManager。您只需调用即可访问最顶层的片段stack.get(stack.size() - 1)

但如果你喜欢 hacks,我必须以其他方式来做类似的事情。我唯一要提的是,这些 hack 只适用于支持片段。

第一个技巧只是将所有活动片段添加到片段管理器中。如果您只是一个接一个地替换片段并从堆栈中弹出,此方法将返回最顶层的片段:

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

第二种方法是事件更 hacky,允许您获取在最后一个事务中添加的所有片段,这些片段addToBackStack已被调用:

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

请注意,在这种情况下,您必须将此类放入android.support.v4.app包中。

于 2016-02-11T22:19:10.963 回答
0

或者您可以在添加与其内容相对应的片段时添加一个标签,并使用简单的静态字符串字段(您也可以将其保存在 onSaveInstanceState(Bundle) 方法中的活动实例包中)来保存最后添加的片段标签并通过Tag() 获取此片段在任何时候你需要...

于 2014-11-03T14:33:56.363 回答
0

Kotlin 开发人员可以使用它来获取当前片段:

        supportFragmentManager.addOnBackStackChangedListener {
        val myFragment = supportFragmentManager.fragments.last()

        if (null != myFragment && myFragment is HomeFragment) {
            //HomeFragment is visible or currently loaded
        } else {
            //your code
        }
    }
于 2020-09-01T07:23:12.447 回答
0

最高(Deepak Goel)的答案对我来说效果不佳。不知何故,标签没有正确添加。

我最终只是通过流(使用意图)发送片段的 ID 并直接从片段管理器中检索它。

于 2017-09-13T17:00:54.297 回答