バックスタックの最新のフラグメントを取得する


104

最新のフラグメントインスタンスをバックスタックに追加するにはどうすればよいですか(フラグメントタグと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 ??

回答:


156

APIレベル14で導入されたのgetName()メソッドを使用できFragmentManager.BackStackEntryます。このメソッドは、を使用してフラグメントをバックスタックに追加したときに使用したタグを返します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);

24
タグでフラグメントを見つけるには、同じタグで追加/置換する必要があります。FragmentTransaction.add(int containerViewId, Fragment fragment, String tag)または FragmentTransaction.replace(int containerViewId, Fragment fragment, String tag) doc
Saqib

3
この問題は、バックスタックにフラグメントが2回ある場合、インデックスまたはバックスタックエントリエンティティしかないと、特定のフラグメントを取得できないことです。
ジャスティン

14
stackpopメソッドでフラグメントにアクセスできない場合、それを呼び出す意味は何ですか?
ケニーワーデン


1
理由はわかりませんが、デバッガーがタグに問題がないことを明確に示していても、findFragmentByTagがnullを返しています。
htafoya 2017

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

2
ルートフラグメントを除くすべてのフラグメントをバックスタックに追加するため、この回答は私のプロジェクトでうまく機能します。しかし、最後に追加されたフラグメントがバックスタックに追加されなかった場合、この回答は機能しないと思います。
Arne Evertsson 2014

40

私は個人的にそれらの解決策の多くを試し、この実用的な解決策に終わりました:

以下の数回使用されるこのユーティリティメソッドを追加して、バックスタック内のフラグメントの数を取得します。

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

お役に立てれば!


10

このヘルパーメソッドは、スタックの最上部からフラグメントを取得します。

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

1
ありがとう。最もエレガントな答え。Kotlin愛好家のためにここに追加しましたstackoverflow.com/a/47336504/1761406
Shirane85


6

fragmentManangerにはフラグメントのリストがあります。フラグメントを削除しても、リストのサイズが減少しないことに注意してください(フラグメントエントリが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
信頼できません。3つの理由:1)これは、スタック上のフラグメントだけでなく、フラグメントマネージャーが認識しているすべてのフラグメントのリストです。2)フラグメントマネージャーがリストの最後に新しいものを追加し続ける保証はありません。確かに、それは簡単なテストでそうしますが、フラグメントが削除されてヌルのままになり、その後、状況によってフラグメントマネージャーがその空のスロットを再利用することを決定した場合はどうなりますか?言っているわけではありませんが、どのような状況でも絶対に行われないという保証はありません。3)あなたまたは将来のプログラマーがアタッチ/デタッチを使用してフラグメントを管理し始める場合、これはスタックと一致しません。
ToolmakerSteve 2016

こんにちは、あなたのソリューションに感謝しますが、それは美しく簡単ではありません
Muhammad Ali

私はそれが実用的な溶液であることを疑います。getFragments()フラグメントの短縮されたコレクションを返します。たぶん最後のものが見えますが、他の多くは見えません。
CoolMind

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

これは、すべてのフラグメントに同じタグを付けた場合にのみ機能します。特定のフラグメントを後で検索する場合はお勧めできません。
Shirane85

4

@roghayeh hosseini(正解)の回答を受け取り、Kotlinで2017年にここで作成しました:)

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

*これはアクティビティ内から呼び出す必要があります。

楽しい :)


3

getBackStackEntryAt()を使用できます。アクティビティがバックスタックに保持するエントリの数を知るには、getBackStackEntryCount()を使用できます。

int lastFragmentCount = getBackStackEntryCount() - 1;

11
しかし、どうすればバックスタックの最後のフラグメントを取得できますか?popBackStackEntryAt()はフラグメントではなく、BackStackEntryインスタンスのみを返します
Leem.fin

はい、そうですが、すべてのBackStackEntryが保持し、getId()で取得できるIDです。このIDを使用してフラグメントを取得できます
Blackbelt

1
最後のフラグメントを取得するには:getBackStackEntryCount()-1
An-droid

3
この答えは間違っています。バックスタックエントリのIDが0であるため、IDでフラグメントを取得できません。
ジャスティン

1
これは古いですが、ここをさまよっている人にとっては、バックスタックはフラグメントを保持していませんが、フラグメントトランザクションを保持しているため、この答えは間違っています
maciekjanusz

3

Deepak Goelの答えに何かを追加します。私を含め、多くの人々が彼の方法を使用してnullを取得していたためです。どうやらフラグメントをバックスタックに追加するときにタグを機能させるには、次のようにする必要があります。

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

同じタグを2回追加する必要があります。

私はコメントしたでしょうが、50の評判はありません。


あなたは今50を持っています:)
davidbilla

2

独自のバックスタックを保持しますmyBackStack。のAddフラグメントとしてFragmentManager、それをに追加しmyBackStackます。でonBackStackChanged()ポップからmyBackStackその長さがより大きい場合getBackStackEntryCount


2

以下のコードは私にとって完璧に機能するので、何かがより良いものに変わったように見えますが、すでに提供されている回答にはそれが見つかりませんでした。

コトリン:

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

Java:

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

2

を使用するとaddToBackStack()、次のコードを使用できます。

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


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直接、あなたが使用する必要がありpush()replace()およびpop()メソッドのFragmentStackManager。また、を呼び出すだけで、最上位のフラグメントにアクセスできますstack.get(stack.size() - 1)

しかし、ハッキングが好きなら、私は他の方法で同様のことをしなければなりません。私が言及しなければならない唯一のことは、これらのハックはサポートフラグメントでのみ機能するということです。

最初のハックは、すべてのアクティブなフラグメントをフラグメントマネージャーに追加することです。フラグメントを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;
  }
}

2番目のアプローチは、イベントのハックで、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)メソッドのアクティビティインスタンスバンドルに保存することもできます)、最後に追加されたフラグメントタグを保持して、このフラグメントbyTag()を取得できます。必要なときにいつでも...


0

最高の(Deepak Goel)回答がうまくいきませんでした。どういうわけか、タグは適切に追加されませんでした。

最終的には、フローを通じて(インテントを使用して)フラグメントのIDを送信し、フラグメントマネージャーから直接取得しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.