获取回退栈中最新的片段

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个回答

3

我想在Deepak Goel 的回答上补充一些内容,因为很多人,包括我在内,使用他的方法时会得到 null。显然,要使标签在将片段添加到后堆栈时起作用,应该按如下方式执行:

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

你需要两次添加相同的标签。
我本来想评论,但我没有50个声望。

1
你现在得到了50分 :) - davidbilla

2
如果你使用addToBackStack(),可以使用以下代码。 List<Fragment> fragments = fragmentManager.getFragments(); activeFragment = fragments.get(fragments.size() - 1); 将原始答案翻译成“最初的回答”。

2
保留自己的后退栈:myBackStack。当你向FragmentManager添加一个fragment时,也将其添加到myBackStack中。在onBackStackChanged()中,当myBackStack的长度大于getBackStackEntryCount时,从myBackStack中弹出。

1
实际上没有将最新的片段添加到堆栈中,因为您可以在单个事务中添加多个或删除片段而不添加新片段。
如果您确实想要拥有片段堆栈,并能够通过其在堆栈中的索引访问片段,则最好在FragmentManager及其回退堆栈上建立抽象层。以下是如何实现:
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来添加和删除片段,而应该使用FragmentStackManagerpush()replace()pop()方法。只需调用stack.get(stack.size() - 1)即可访问最顶部的片段。
但是,如果您喜欢黑客技巧,我还有其他几种类似的方法。需要注意的是,这些黑客技巧仅适用于支持片段。
第一个黑客技巧就是获取所有添加到片段管理器中的活动片段。如果您只是逐个替换片段并从堆栈中弹出它们,那么此方法将返回最顶部的片段:
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包中。

0
或者,您可以在添加对应内容的片段时添加标记,并使用简单的静态字符串字段(也可以在onSaveInstanceState(Bundle)方法中保存在活动实例包中),以保存最后添加的片段标记,并随时通过getFragmentByTag()获取该片段。...

0

最高票答案(Deepak Goel)对我来说效果不佳。某种程度上,标签没有被正确添加。

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


0

Kotlin开发者可以使用以下代码获取当前的Fragment:

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

        if (null != myFragment && myFragment is HomeFragment) {
            //HomeFragment is visible or currently loaded
        } else {
            //your code
        }
    }

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