これは、深くネストされたスタックを離れるときにフラグメントバックスタックをクリーンアップする正しい方法ですか?


130

Android互換性ライブラリを使用してフラグメントを実装し、レイアウトサンプルを拡張して、別のフラグメントを起動するボタンがフラグメントに含まれるようにしました。

左側の選択ペインには、5つの選択可能なアイテムがあります- A B C D E

それぞれがFragmentTransaction:replace詳細ペインに(を介して)フラグメントをロードします-a b c d e

ここでe、フラグメントを拡張e1して、詳細ペインにも別のフラグメントをロードするボタンを含めました。e次のように、フラグメントのonClickメソッドでこれを行いました。

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details_frag, newFrag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();

次の選択を行った場合:

E - e - e1 - D - E

次に、フラグメントeは詳細ペインにあります。これで結構です。ただし、backこの時点でボタンを押しても何も起こりません。e1まだスタックにあるので、2回クリックする必要があります。さらに、クリックした後、onCreateViewでnullポインター例外が発生しました。

この問題を「解決」するために、A B C D Eが選択されている場合は常に次のコードを追加しました。

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
    fm.popBackStack();
}

これが正しい解決策であるか、それとも私が何か別のことをするべきかどうか疑問に思っていますか?

回答:


252

まあ、意図された動作に応じてこれに対処するいくつかの方法がありますが、このリンクはあなたにすべての最良の解決策を与えるはずであり、当然のことながら、ダイアンハックボーンからです

http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42

基本的に、次のオプションがあります

  • 初期のバックスタック状態の名前を使用し、を使用します FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)
  • FragmentManager.getBackStackEntryCount()/ getBackStackEntryAt().getId() を使用して、バックスタックの最初のエントリのIDを取得します FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE)
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) バックスタック全体をポップすることになっています...そのためのドキュメントは間違っていると思います。(実際、私はそれがあなたが渡すケースをカバーしていないと思いますPOP_BACK_STACK_INCLUSIVE)、

これは何を意味するのでしょうか?FragmentManager.getBackStackEntryCount()/ getBackStackEntryAt()。getId()
dannyroa

4
2番目は私のために働いた。スタック全体をクリアすることの意味:getSupportFragmentManager()。popBackStack(getSupportFragmentManager()。getBackStackEntryAt(0).getId()、FragmentManager.POP_BACK_STACK_INCLUSIVE);
NickL 2012年

@JorgeGarciaは、popbackstackの後で、古いフラグメントを再起動せずにフラグメントを終了することは可能ですか?
duggu 2013

popBackStack()は非同期であるため、popBackStackImmediate()バージョンもあることに注意してください。つまり、メソッドを呼び出した瞬間にクリアが発生しません。
Gencは2016

6
グループがスパムとして禁止されており、リンクにアクセスできないと主張している:(誰か他の場所にリソースを持っていますか?
EpicPandaForce

61

すべてのスタックエントリをポップしたくない場合のもう1つのクリーンなソリューション...

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_container, fragmentInstance).addToBackStack(null).commit();

これにより、最初にスタックがクリーンアップされてから新しいフラグメントが読み込まれるため、どの時点でもスタックにはフラグメントが1つしかありません。


1
これは非常に悪いです:getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);交換する前に()フラグメントの呼び出しをロードしているのでonCreateView()onActivityCreated()など、復元およびフラグメントは瞬時に悪いですDestroing。Fragmentは、たとえばレシーバーを登録できます。これはパフォーマンスに影響します。
VasileM

@VasileM、詳しく説明していただけますか?どのような場合にそれは悪いですか?の非同期行動のためFragmentTransactionですか?間違ったフラグメントスタックのパフォーマンスが悪いだけですか?
CoolMind

27

Joachimの回答のおかげで、コードを使用して最終的にすべてのバックスタックエントリをクリアしました。

// In your FragmentActivity use getSupprotFragmentManager() to get the FragmentManager.

// Clear all back stack.
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < backStackCount; i++) {

    // Get the back stack fragment id.
    int backStackId = getSupportFragmentManager().getBackStackEntryAt(i).getId();

    getSupportFragmentManager().popBackStack(backStackId, 
        FragmentManager.POP_BACK_STACK_INCLUSIVE);

} /* end of for */

18
なぜここでループを使用するのですか?私にとっては、FragmentManager.popBackStack(null、FragmentManager.POP_BACK_STACK_INCLUSIVE)がすべてのバックスタックエントリをクリアしました...
Marek

3
@Marek、すべてのフラグメントを削除する必要がない場合があるため、ループはこれに適しています。
CoolMind

1
@CoolMind、それはまだ私には意味がありません。popBackStack(backStackId, INCLUSIVE)すべてのフラグメント(状態)をbackStackIdにポップiします。そのため、ポップする最も低いフラグメントをポップすると、より高いフラグメントがすべて同時にポップされます。では、ループのポイントは何ですか?
LarsH

@LarsH、あなたは正しい。stackoverflow.com/a/59158254/2914140を参照してください。他のフラグメントを必要なタグにポップするには、最初にフラグメントをaddToBackStack(tag)で追加する必要があります。
CoolMind

7

私はバックスタックを掃除するために多くを研究しました、そして最後に Transaction BackStackとその管理について説明します。これが私にとって最も効果的な解決策です。

 // CLEAR BACK STACK.
    private void clearBackStack() {
        final FragmentManager fragmentManager = getSupportFragmentManager();
        while (fragmentManager.getBackStackEntryCount() != 0) {
            fragmentManager.popBackStackImmediate();
        }
    }

上記のメソッドは、バックスタック内のすべてのトランザクションをループし、一度に1つずつそれらを即座に削除します。

注意:上記のコードは機能しない場合があり、このコードのためにANRに直面するため、これを試さないでください。

更新 以下のメソッドをすると、その「名前」のすべてのfregmentがバックスタックから削除されます。

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
  • name nullでない場合、これは検索する前のバック状態の名前です。見つかった場合、その状態までのすべての状態がポップされます。の
  • POP_BACK_STACK_INCLUSIVEフラグを使用して、名前付き状態自体をポップするかどうかを制御できます。nullの場合、トップ状態のみがポップされます。

それらを一度に1つずつ削除する理由がわかりません。他のソリューションではなくこのソリューションを選択した理由はありますか?それらを一度にすべてではなく一度に1つずつ削除する理由はありますか?
miva2

一度にバックスタックを削除する方法はありません。developer.android.com/ reference / android / app /…を参照して
Lokesh

3

whileループを使用するコードと同様のコードを使用していますが、すべてのループでエントリ数を呼び出しています...なので、少し遅いと思います

FragmentManager manager = getFragmentManager();
while (manager.getBackStackEntryCount() > 0){
        manager.popBackStackImmediate();
    }

0

書かれたようbackstackオフの断片をポップする方法とによってLarsHここで、我々は(specificalタグに上から下にいくつかの断片を開くことができます一緒にタグ付けされた断片と、このメソッドを使用して):

fragmentManager?.popBackStack ("frag", FragmentManager.POP_BACK_STACK_INCLUSIVE);

「frag」をフラグメントのタグに置き換えます。最初にフラグメントをバックスタックに追加する必要があることを覚えておいてください:

fragmentTransaction.addToBackStack("frag")

でフラグメントを追加する場合addToBackStack(null)、フラグメントをそのようにポップすることはありません。


-4
    // pop back stack all the way
    final FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
    int entryCount = fm.getBackStackEntryCount(); 
    while (entryCount-- > 0) {
        fm.popBackStack();
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.