[解決済み] Android Fragmentのバックスタックに関する問題
質問
アンドロイドのフラグメントバックスタックが動作する方法について、大きな問題を抱えています。
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()
のメソッドを使用します。
- トランザクションのカウントをトレースします。
-
名前による特定のトランザクションの確認
FragmentTransaction.addToBackStack(String name);
- などなど。
関連
-
[解決済み] Androidのソフトキーボードをプログラムで閉じる/隠すにはどうすればよいですか?
-
[解決済み] Androidでアクティビティ起動時にEditTextにフォーカスが当たらないようにする方法
-
[解決済み] Androidの「コンテキスト」とは何ですか?
-
[解決済み] FragmentでonActivityResultが呼び出されない
-
[解決済み] 新しいAndroid Fragmentをインスタンス化するためのベストプラクティス
-
[解決済み】Android UserManager.isUserAGoat()の正しい使用例?)
-
[解決済み] フラグメント・イン・フラグメント
-
[解決済み] アンドロイドフラグメント onRestoreInstanceState
-
[解決済み] アプリ内課金テスト:android.test.purchased already owned
-
[解決済み] Receiver not registered exception error?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] プログラム的に電話をかけるには?
-
[解決済み] CardView layout_width="match_parent "が親のRecyclerViewの幅と一致しない。
-
[解決済み] AndroidでラジオボタンにOnClickListenerを設定するには?
-
[解決済み] Android ConstraintLayout - あるビューを別のビューの上に配置する
-
[解決済み] アンドロイドアプリのユーザーデータを消去する
-
[解決済み] バイト配列の画像ファイルをビットマップに変換するには?
-
[解決済み] Android: ランドスケープモード用の代替レイアウト xml
-
[解決済み] Android - Snackbar vs Toast - 使い方と違い。
-
[解決済み] アンドロイドでシェイクを検出するには?
-
[解決済み] Android: xml リソースからの整数値