フラグメントを使用してバックスタックをクリアする


244

Androidアプリをハニカムに移植し、フラグメントを使用するために大きなリファクタリングを行いました。以前のバージョンでは、ホームボタンを押すとACTIVITY_CLEAR_TOP、バックスタックをリセットするためにaを使用していました。

これで、私のアプリは複数のフラグメントを持つ単一のアクティビティになりました。ホームボタンを押すと、その中のフラグメントの1つを置き換えるだけです。どのように私は使用せずに私の背中スタックをクリアできるstartActivityACTIVITY_CLEAR_TOPフラグ?


バックスタックの使用は避けてください!それは全体的な効率を実際には助けません!単純なreplace()を使用するか、ナビゲートするたびに削除/追加してください!stackoverflow.com/questions/5802141/…で
stack_ved

回答:


430

ここに似たようなものを投稿しました

ヨアヒムの答えから、ダイアン・ハックボーンから:

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

私は結局使用しました:

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

しかし、同様に次のようなものを使用することもできます:

((AppCompatActivity)getContext()).getSupportFragmentManager().popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)

名前付きの状態までのすべての状態をポップします。次に、フラグメントを必要なものに置き換えるだけです


8
これは、戻るボタンを1回以上押すのと同じなので、現在表示されているフラグメントを変更します。(少なくとも私が試したとき)
Peter Ajtai

7
ピーターと同じ問題があります。私は、多くの意味を持っているそれらを循環させるのではなく、すべての断片を一掃したいと思います。たとえば、スタックからすべてのフラグメントを順番にポップすることで、不要なライフサイクルイベントにヒットします。
Brian Griffey

233
先頭に移動するには、次を使用します。fragmentManager.popBackStack(null、FragmentManager.POP_BACK_STACK_INCLUSIVE);
Warpzit 2013年

53
その価値のために、fragmentManagerを使用します。popBackStackImmediate(null、FragmentManager.POP_BACK_STACK_INCLUSIVE); フラグメントアニメーションの実行が妨げられたため、私にはさらに効果がありました
roarster

17
これは適切に機能しません-間にあるすべてのフラグメントのonStartの呼び出しをトリガーします
James

165

@Warpzitのコメントに回答し、他のユーザーが見つけやすくするため。

使用する:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

14
AppCompatActivityを使用すると、このようにバックスタックからすべてのフラグメントをポップすることが、最新のv7-appCompatライブラリで壊れていると思います。アプリを最新のv7-appCompatライブラリ(21.0.0)に更新し、新しいAppCompatActivityを拡張した後、上記の方法でフラグメントをポップすると、FragmentManagerのバックスタックレコードにいくつかのフラグメントが残ります。これを使用しないことをお勧めします。
dell116

popBackStackImmediateを使用できます。
Kannan_SJD

38

すべての関係者に敬意を払います。簡単な操作でフラグメントバックスタック全体をクリアできる人がどれだけいるのか見て、私はとても驚いています。

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Androidのドキュメントによると(name主張に関して-主張された作業中の提案の「null」)。

nullの場合、トップ状態のみがポップされます

今、私はあなたの特定の実装(特定の時点でバックスタックにあるエントリの数など)についての知識が不足していることを理解していますが、明確に定義されていることを期待するとき、私はすべてのお金を受け入れられた答えに賭けるでしょう幅広いデバイスとベンダーでの動作:

(参考として、これと一緒に何か)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}

4
私にとっては、各ポップが内部で各フラグメントのonCreateViewに移動するためでした。どこかのリソースでNPEを受け取る場所。ただし、fm.popBackStack(null、FragmentManager.POP_BACK_STACK_INCLUSIVE);を使用します。単にすべてのバックスタックを殺した。
sud007

1
ループを使用してポップするときにonCreateView呼び出しをスキップする方法についての洞察はありますか?
Ayush Goyal

最上位のフラグメント(null)をクリアすると、バックスタックでそれ以降のすべてのフラグメントがクリアされます。
2b77bee6-5445-4c77-b1eb-4df3e5 2017

18

ループを使用せずに私にとっては簡単な方法で動作します:

 FragmentManager fragmentManager = getSupportFragmentManager();
 //this will clear the back stack and displays no animation on the screen
 fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

17

受け入れられた答えは私にとって十分ではありませんでした。私は使用しなければなりませんでした:

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

2
これは別の答えで指摘されましたが、注意してください:スタック全体をこのようなループでポップすると、スタックの開始と終了の間のすべてのフラグメントのライフサイクルメソッドがトリガーされます。ほとんどのユースケースでは、この実装が意図しない結果をもたらす可能性が十分にあります。popBackStackImmediate()トランザクションを同期的に実行することも指摘する価値があります。これは、一般的には不適切です。
Damien Diehl

16

ループなしでバックスタックをクリア

String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);

どこに名前が addToBackStack()パラメータであり、

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)

u replace .fragmentスタックが存在しても表示されない場合でも
Asthme

8

追加したかっただけです:-

以下を使用してバックスタックからポップアウト

fragmentManager.popBackStack()

トランザクションからフラグメントを削除するだけであり、画面からフラグメントを削除する方法はありません。したがって、理想的には見えないかもしれませんが、2つまたは3つのフラグメントが重なり合っており、戻るキーを押すと、UIが雑然として積み重なっているように見えることがあります。

簡単な例を挙げましょう:-

fragmentmanager.replace()を使用してFragmnet BをロードするfragmentAがあるとします。その後、このトランザクションを保存するためにaddToBackStackを実行します。したがって、フローは:-

ステップ1-> FragmentA-> FragmentB(FragmentBに移動しましたが、フラグメントAはバックグラウンドにあり、表示されません)。

次に、フラグメントBでいくつかの作業を行い、[保存]ボタンを押します。保存すると、フラグメントAに戻ります。

ステップ2-> FragmentBを保存すると、FragmentAに戻ります。

ステップ3->よくある間違いは...フラグメントBでは、フラグメントManager.replace()フラグメントBをフラグメントAで実行します。

しかし実際に起こっていることは、フラグメントAを再度ロードして、フラグメントBを置き換えることです。これで、2つのFragmentAがあります(1つはSTEP-1から、もう1つはこのSTEP-3から)。

FragmentsAの2つのインスタンスは互いに重なり合っているため、表示されない場合がありますが、存在しています。

したがって、上記の方法でバックスタックをクリアしても、トランザクションはクリアされますが、実際のフラグメントはクリアされません。したがって、このような特定の場合に理想的には、保存ボタンを押したときに、fm.popBackStack()またはfm.popBackImmediate()を実行するだけで、fragmentAに戻る必要があります。

正しいStep3-> fm.popBackStack()は、すでにメモリにあるfragmentAに戻ります。


3

ドキュメントを読み、フラグメントIDが何であるかを調べると、それは単にスタックインデックスのように見えるため、これは機能します。

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

ゼロ(0)はスタックの一番下なので、そこまでポップアップするとスタックがクリアされます。

警告:上記は私のプログラムでも機能しますが、FragmentManagerのドキュメントには実際にはidがスタックインデックスであると記載されていないため、少し迷っています。それはそうであるということは理にかなっており、私のすべてのデバッグログはそれが何であるかを明らかにしますが、おそらくいくつかの特別な状況ではそうしませんか?誰かがこれを何らかの方法で確認できますか?そうであれば、上記が最良の解決策です。そうでない場合は、これが代替手段です。

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }

1
fragmentManager..getBackStackEntryAt(0).getId()0の代わりに使用するのはどうですか?これは、バックスタックエントリIDがスタックインデックスと異なる場合でも機能します。
ChristophK

3

このメソッドを使用して、バックステークフラグメントを削除する必要があるまでContext&Fragmentタグを渡します。

使用法

clearFragmentByTag(context, FragmentName.class.getName());



public static void clearFragmentByTag(Context context, String tag) {
    try {
        FragmentManager fm = ((AppCompatActivity) context).getSupportFragmentManager();

        for (int i = fm.getBackStackEntryCount() - 1; i >= 0; i--) {
            String backEntry = fm.getBackStackEntryAt(i).getName();
            if (backEntry.equals(tag)) {
                break;
            } else {
                 fm.popBackStack();
            }
        }
    } catch (Exception e) {
        System.out.print("!====Popbackstack error : " + e);
        e.printStackTrace();
    }
}

2

こんにちは〜私はより良い解決策を見つけました:https : //gist.github.com/ikew0ng/8297033

    /**
 * Remove all entries from the backStack of this fragmentManager.
 *
 * @param fragmentManager the fragmentManager to clear.
 */
private void clearBackStack(FragmentManager fragmentManager) {
    if (fragmentManager.getBackStackEntryCount() > 0) {
        FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
        fragmentManager.popBackStack(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }
}

2
このソリューションの方が優れている理由をお答えください。
Simon.SA 2018年

SDKが提供するメカニズムを使用しており、NPEの問題は発生しません。
Chenxi、

1

私はこれをこのように機能させました:

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}

1

それは私のために働いています、これを試してください:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }

0
    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

このメソッドの呼び出しは非常に便利です。

  1. ループは必要ありません。
  2. フラグメントでアニメーションを使用している場合、あまり多くのアニメーションは表示されません。しかし、ループを使用することはできます。

0
private boolean removeFragFromBackStack() {
    try {
        FragmentManager manager = getSupportFragmentManager();
        List<Fragment> fragsList = manager.getFragments();
        if (fragsList.size() == 0) {
            return true;
        }
        manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

このコードスニペットをありがとうございます。このコードスニペットは、制限された即時のヘルプを提供する可能性があります。適切な説明が大幅にこれは問題に良い解決策であり、他、同様の質問を将来の読者にそれがより便利になるだろう、なぜ示すことによって、その長期的な価値を向上させるであろう。回答を編集して、仮定を含めて説明を追加してください。
Abdelilah El Aissaoui
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.