フラグメントをそれ自体を削除する方法、つまり、finish()と同等のものを取得するにはどうすればよいですか?


230

互換性ライブラリを使用して、フラグメントを使用するようにアプリを変換しています。現在、私には互いに連鎖するいくつかのアクティビティ(ABCD)があります。Dには[OK]ボタンがあります。このボタンを押すと、通話が終了すると、onActivityResult()CとBをさらに破壊するためにバブルアップします。

私のHonycombフラグメント前のバージョンでは、各アクティビティは事実上、フラグメントAf Bf Cf Dfのラッパーです。すべてのアクティビティは、フラグメントのそれぞれを介して起動されstartActivityForResult()onActivityResult()喜んで呼び出すことができますgetActivity().finish()

私が抱えている問題はHoneycombバージョンにあります。私は1つのアクティビティAのみを持ち、フラグメントBf、Cf、Dfはを使用してロードされFragmentManagerます。

Df、Cf、Bfのフラグメントを削除するために「OK」が押されたときにDfで何をすればよいのかわかりません。

フラグメントをスタックからポップアウトさせようとしましたが、これにより例外が発生しました。onActivityResult()を使用してフラグメントをロードしていないため、役に立たないstartActivityForResult()

私はこれを完全に間違った方法で考えていますか?トランザクションマネージャーを使用してポップを行うために、親フラグメントまたはアクティビティーと通信するある種のリスナーを実装する必要がありますか?


7
((YourActivity)getActivity())。onBackPressed();についてはどうですか
Viswanath Lekshmanan 2015年

あなたのコメントの答えは私から... 1 Upvote私のために有用である@ViswanathLekshmanan
アビシェーク・シン

@AbhishekSingh聞いてよかった:)
Viswanath Lekshmanan

@ViswanathLekshmanan :)
Abhishek Singh

回答:


62

Df、Cf、Bfのフラグメントを削除するために「OK」が押されたときにDfで何をすればよいのかわかりません。

ステップ#1:DfにDに「yo!我々はOKクリックを得た!」アクティビティ自体で、またはアクティビティによって提供されるインターフェースインスタンスでメソッドを呼び出す。

ステップ#2:Dにからフラグメントを削除してもらいFragmentManagerます。

ホスティングアクティビティ(D)は、他のフラグメントがアクティビティに含まれている(他のアクティビティに含まれている)ことを知っているアクティビティです。したがって、フラグメントミックスに影響を与える可能性のあるフラグメント内のイベントは、適切なオーケストレーションを動かすアクティビティに伝播する必要があります。


しかし、私のHoneycombバージョンにはDがありません。FragmentTransactionを使用してDfをロードするCfをロードするフラグメントBfをロードするアクティビティAがあります。
PJL

1
@PJL:申し訳ありませんが、私はAを意味しました。これがリスナーインターフェイスを使用する理由の1つです。そのため、複数のアクティビティはすべて、Dfから「OKクリック」イベントに応答できます。
CommonsWare、2011

1
現在移植しているので、フラグメントのDfのonActivityResultメソッドからアクティビティにリスナーメソッドを呼び出し、それからFragmentManagerでpopBackStackを呼び出しました。ただし、これにより例外「IllegalStateException:onSaveInstanceStateの後でこのアクションを実行できません」が発生します。これを克服する方法に関するアイデアはありますか?
PJL

1
@DiegoPalomar:finish()十分です。
CommonsWare 2013

1
@ user3364963:調査してからしばらく経ちますが、IIRCでは、バックスタックから外されると破壊されます。onDestroy()メソッドをフラグメントに追加し、それが呼び出されるかどうかを確認します。
CommonsWare 2014年

313

それが最善のアプローチではないかもしれませんが、私がうまくいくと考えることができる最も近い同等のものは、サポート/互換性ライブラリを使用したこれです

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

または

getActivity().getFragmentManager().beginTransaction().remove(this).commit();

さもないと。

さらに、バックスタックを使用してポップすることもできます。ただし、フラグメントがバックスタックにない場合があります(フラグメントを取得したフラグメントトランザクションによっては)。スタックに到達した最後のフラグメントではない可能性があるため、スタックをポップすると、間違ったフラグメントが削除される場合があります。


11
このアプローチは機能しますが、addToBackStack(null)を使用している場合、戻るボタンハンドラーは+1のままになります。したがって、2回押す必要があります。
user123321 2012年

34
FragmentManagerからフラグメントを「ポップ」します。
user123321 2012年

2
上記の手順を試しましたが、「java-lang-illegalstateexception-can-not-perform-this-action-after-onsaveinstance」というエラーが発生します。だから私は正確にフラグメントを削除する必要があります
KK_07k11A0585

6
この答えは悪い習慣であり、投票を獲得するべきではありません。フラグメントは、このように自覚することを意図していません。フラグメントのポイントである再利用性が失われます!フラグメントは、任意の数の手段でそれを削除するアクティビティを通知する必要があります。コールバックインターフェイスメソッドは、一般的な選択肢です。developer.android.com/training/basics/fragments/...
colintheshots

2
@ManfredMoser同意しない。これが問題のポイントです。彼には、削除するフラグメントのシーケンス全体があります。このコードには、nullチェックがないか、アクティビティがアタッチされているかどうかがチェックされます。それはフラグメントが知らないあまりにも多くの事柄に依存するので、それは本番で壊れます。
colintheshots

263

あなたは以下のアプローチを使うことができます、それはうまくいきます:

getActivity().getSupportFragmentManager().popBackStack();

44
この答えは、受け入れられた答えよりも10倍優れています。
nikib3ro 2013

50
また、デザインに関しては、受け入れられているものよりも10倍劣っています。フラグメントはアクティビティの小さな「ヘルパー」であると想定されており、それ自体または他のフラグメントを制御することはできません
Patrick

6
@avalanchaが指摘したように、解決策は正しくありません。見ていdeveloper.android.com/guide/components/...を
the_dark_destructor

2
このメソッドonActivityResultを使用していて、「onSaveInstanceStateの後でこのアクションを実行できません」というエラーが発生します。どうすれば解決できますか?
Jayeshkumar Sojitra

1
popBackStack()フラグメントを削除した後でアクションバーのタイトルを以前の状態に戻したい場合に機能する唯一のソリューションです。それ以外の場合は、stackoverflow.com / questions / 13472258 / …の両方の高評価ソリューションと、ここでのこのソリューションを組み合わせて、さまざまなユースケースの後で常に適切なアクションバータイトルを設定する必要はありません。バックプレス、削除、置換の追加など。
2016年

36

CommonsWareが言うように、リスナーを使用して、アクティビティにフラグメントの追加と削除を処理させる必要があります。次に例を示します。

public class MyActivity extends FragmentActivity implements SuicidalFragmentListener {

    // onCreate etc

    @Override
    public void onFragmentSuicide(String tag) {
        // Check tag if you do this with more than one fragmen, then:
        getSupportFragmentManager().popBackStack();
    }
}

public interface SuicidalFragmentListener {
    void onFragmentSuicide(String tag);
}

public class MyFragment extends Fragment {

    // onCreateView etc

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
           suicideListener = (SuicidalFragmentListener) activity;
        } catch (ClassCastException e) {
           throw new RuntimeException(getActivity().getClass().getSimpleName() + " must implement the suicide listener to use this fragment", e);
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // Attach the close listener to whatever action on the fragment you want
        addSuicideTouchListener();
    }

    private void addSuicideTouchListener() {
        getView().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              suicideListener.onFragmentSuicide(getTag());
            }
        });
    }
}

5
自殺くらいのエモスタイル?「SelfClosing」または「AutoClose」または「SmartClose」(r)についてはどうですか
DritanX 14

21
それは閉じていませんDYING FOREVER ;-(
Blundell

3
これは他の回答よりもはるかにクリーンなアプローチです。アクティビティはフラグメントを作成して提示し、そのライフサイクルを制御する必要があります。フラグメントが表示されなくなったことを示す何かが発生した場合は、アクティビティにそのことを通知し、アクティビティに削除させる必要があります。
Christopher Pickslay 14

7
厳密には、アクティビティでフラグメントを強制終了することになっている場合、フラグメントは自殺的ではありません。活動は殺人です。
Casey Murray

17

Activity / AppCompatActivityで:

@Override
public void onBackPressed() {
    if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        // if you want to handle DrawerLayout
        mDrawerLayout.closeDrawer(GravityCompat.START);
    } else {
        if (getFragmentManager().getBackStackEntryCount() == 0) {
            super.onBackPressed();
        } else {
            getFragmentManager().popBackStack();
        }
    }
}

そしてフラグメントを呼び出します:

getActivity().onBackPressed();

または他の回答で述べたように、これをフラグメントで呼び出します:

getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

5

新しいナビゲーションコンポーネントを使用している場合は、次のように簡単です。

findNavController().popBackStack()

すべてのFragmentTransactionが背後で実行されます。


4

DialogFragmentによってニーズが満たされているかどうかを確認します。DialogFragmentにはdismiss()メソッドがあります。私の意見でははるかにきれいです。


3

そのための簡単なメソッドを作成します

popBackStack(getSupportFragmentManager());

私のActivityUtilsクラスに配置するより

public static void popBackStack(FragmentManager manager){
        FragmentManager.BackStackEntry first = manager.getBackStackEntryAt(0);
        manager.popBackStack(first.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

それは素晴らしい仕事です、楽しんでください!


2
私はあなたの方法の目的を理解していません。オリジナルのpopBackStackは完全に適切なようです。
信じられないほどの月

1

OnCreate:

//Add comment fragment
            container = FindViewById<FrameLayout>(Resource.Id.frmAttachPicture);
            mPictureFragment = new fmtAttachPicture();

            var trans = SupportFragmentManager.BeginTransaction();
            trans.Add(container.Id, mPictureFragment, "fmtPicture");
            trans.Show(mPictureFragment); trans.Commit();

これは、クリックイベント1でフラグメントを非表示にする方法です。

//Close fragment
    var trans = SupportFragmentManager.BeginTransaction();
    trans.Hide(mPictureFragment);
    trans.AddToBackStack(null);
    trans.Commit();

次に、それをintイベント2に表示します。

var trans = SupportFragmentManager.BeginTransaction();
            trans.Show(mPictureFragment); trans.Commit();

1

バックスタック履歴の4番目のフラグメントから最初のフラグメントにポップバックする必要がある場合は、タグを使用してください!!!

最初のフラグメントを追加するときは、次のようなものを使用する必要があります。

getFragmentManager.beginTransaction.addToBackStack("A").add(R.id.container, FragmentA).commit() 

または

getFragmentManager.beginTransaction.addToBackStack("A").replace(R.id.container, FragmentA).commit()

また、フラグメントB、C、Dを表示する場合は、次のようにします。

getFragmentManager.beginTransaction.addToBackStack("B").replace(R.id.container, FragmentB, "B").commit()

その他の文字...

FragmentAに戻るにはpopBackStack(0, "A")、yesを呼び出すだけです。追加するときに指定したフラグを使用します。これは、コマンドのフラグと同じでなければならaddToBackStack()ず、replaceコマンドやaddコマンドで使用するフラグではないことに注意してください。

どういたしまして ;)


「popBackStack(0、 "A")」をテストしましたが、アプリがフラグメントAに戻りますが、そのフラグメントのみがバックスタックから削除されます...画面に表示せずにスタックからフラグメントを削除するにはどうすればよいですか?
KryNaC 2015年


-9

なぜか:

getActivity()。finish();


4
これにより、フラグメントだけでなくアクティビティ全体が終了します。
Murtadha S.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.