1. ホーム
  2. android

[解決済み] Android Fragmentのバックスタックに関する問題

2022-07-23 15:38:23

質問

アンドロイドのフラグメントバックスタックが動作する方法について、大きな問題を抱えています。

3つのフラグメントがあるとします。

[1] [2] [3]

ユーザがナビゲートできるようにしたい [1] > [2] > [3] を移動できるが、戻るとき(戻るボタンを押すとき)に [3] > [1] .

私が想像していた通り、これは addToBackStack(..) を呼び出さないことです。 [2] をXMLで定義されたフラグメントホルダーに入れるトランザクションを作成するとき。

この現実は、もし私が [2] で戻るボタンを押したときに、再び [3] を呼び出してはいけません。 addToBackStack を呼び出してはいけません。 [3] . これは完全に直感に反しているように見えます (おそらく iOS の世界から来たものでしょう)。

とにかく、この方法でやると、私は [1] > [2] に戻り、押し戻すと [1] に戻る。

もし私が [1] > [2] > [3] と進み、戻るを押すと [1] (にジャンプします(予想通り)。 今、奇妙な動作が起こるのは [2] から再び [1] . まず最初に [3] が短く表示される前に [2] が表示されます。この時点で押し戻すと [3] が表示され、もう一度 "戻る "を押すとアプリが終了します。

どなたか、何が起こっているのか理解するのにご協力いただけないでしょうか?



そして、これは私の主な活動のためのレイアウトxmlファイルです。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:orientation="vertical" >

<fragment
        android:id="@+id/headerFragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        class="com.fragment_test.FragmentControls" >
    <!-- Preview: layout=@layout/details -->
</fragment>
<FrameLayout
        android:id="@+id/detailFragment"
        android:layout_width="match_parent"
        android:layout_height="fill_parent"

        />





更新 これは、ナビゲーションの階層を構築するために私が使っているコードです。

    Fragment frag;
    FragmentTransaction transaction;


    //Create The first fragment [1], add it to the view, BUT Dont add the transaction to the backstack
    frag = new Fragment1();

    transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.detailFragment, frag);
    transaction.commit();

    //Create the second [2] fragment, add it to the view and add the transaction that replaces the first fragment to the backstack
    frag = new Fragment2();

    transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.detailFragment, frag);
    transaction.addToBackStack(null);
    transaction.commit();


    //Create third fragment, Dont add this transaction to the backstack, because we dont want to go back to [2] 
    frag = new Fragment3();
    transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.detailFragment, frag);
    transaction.commit();


     //END OF SETUP CODE-------------------------
    //NOW:
    //Press back once and then issue the following code:
    frag = new Fragment2();
    transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.detailFragment, frag);
    transaction.addToBackStack(null);
    transaction.commit();

    //Now press back again and you end up at fragment [3] not [1]

ありがとうございます。

どのように解決するのですか?

説明:ここで何が起こっているのかについて?

もし私たちが .replace() と同じです。 .remove().add() と等しいことをドキュメントで知っています。

コンテナに追加された既存のフラグメントを置き換えます。これは本質的には remove(Fragment) で追加されたすべてのフラグメントに対して、同じ containerViewId で追加され、その後 add(int, Fragment, String) をここで与えられたのと同じ引数で実行します。

とすると、起こっていることは次のようになります(わかりやすくするためにfragに数字を付けています)。

// transaction.replace(R.id.detailFragment, frag1);
Transaction.remove(null).add(frag1)  // frag1 on view

// transaction.replace(R.id.detailFragment, frag2).addToBackStack(null);
Transaction.remove(frag1).add(frag2).addToBackStack(null)  // frag2 on view

// transaction.replace(R.id.detailFragment, frag3);
Transaction.remove(frag2).add(frag3)  // frag3 on view

(ここですべての誤解を招くようなことが起こり始める)

以下のことを忘れないでください。 .addToBackStack() が保存しているのは トランザクション ではなく フラグメント をそのまま使っているのではありません。というわけで、今、私たちは frag3 をレイアウト上に置くことができます。

< press back button >
// System pops the back stack and find the following saved back entry to be reversed:
// [Transaction.remove(frag1).add(frag2)]
// so the system makes that transaction backward!!!
// tries to remove frag2 (is not there, so it ignores) and re-add(frag1)
// make notice that system doesn't realise that there's a frag3 and does nothing with it
// so it still there attached to view
Transaction.remove(null).add(frag1) //frag1, frag3 on view (OVERLAPPING)

// transaction.replace(R.id.detailFragment, frag2).addToBackStack(null);
Transaction.remove(frag3).add(frag2).addToBackStack(null)  //frag2 on view

< press back button >
// system makes saved transaction backward
Transaction.remove(frag2).add(frag3) //frag3 on view

< press back button >
// no more entries in BackStack
< app exits >

可能な解決策

以下のような実装を検討する。 FragmentManager.BackStackChangedListener を実装してバックスタックの変化を監視し、ロジックを onBackStackChanged() のメソッドを使用します。