web-dev-qa-db-ja.com

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

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

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

127
PJL

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

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を渡す場合をカバーしていないと思います)、
248
Joachim

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

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

これにより、最初にスタックがクリーンアップされ、次に新しいフラグメントがロードされるため、どの時点でもスタック内に単一のフラグメントしかありません

60

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

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

    fm.popBackStack(backStackId, FragmentManager.POP_BACK_STACK_INCLUSIVE);

} /* end of for */
25
Jay Parker

Backstackをクリーニングするために多くのことを研究し、最終的に Transaction BackStackとその管理 を参照しました。これが私に最適なソリューションです。

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

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

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

Update以下のメソッドは、バックスタックからその「名前」の断片をすべて削除します。

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

Whileループを使用するコードと同様のコードを使用していますが、すべてのループでエントリカウントを呼び出しています...

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