FragmentのMultiple back stacks

Kenji Abe
May 23, 2021
Photo by La-Rel Easter on Unsplash

Fragment 1.4.0-alpha01 よりMultiple back stacksの対応が導入されました。この対応で新しいAPIが追加されてるので、使い方と振る舞いについて見ていきます。

おそらく、基本的に直接これらのAPIを使うことはなく Navigation Component を通して使うことが多いと思います。

注意

まだリリース直後のalpha01で試しているため、今後変更がある可能性が高いです。

新しいAPI

saveBackStackrestoreBackStack のAPIが新たに追加されていて、これらを使ってMultiple back stacksを実現していきます。

saveBackStack

こちらのAPIは addToBackStack で指定した名前を使用します。挙動としては popBackStack と同じような動作になりますが、あとから復元できるようにBack stackを保存します。

restoreBackStack

saveBackStack で保存したBack stackをあとから復元してFragmentを再表示します。

ドキュメントではBack stackを保存という記述になっていますが、個人的にはdetach/attachに近いのかなって思っています。

使用方法

使用例をいくつか見ながら説明していきます。

例1

まずは単純に2つのFragment使用します。

で、そのあとに、 saveBackStack で Back stackを保存します。

supportFragmentManager.saveBackStack("backstack1")

この結果を図にすると以下のようになります。

2番目のFragmentは popBackStack と同様のことが行われ、状態が保存されます。その結果として、最初のFragmentが表示されことになります。

例2

例1を実行後の状態から次に restoreBackStack を使って復元をしてみます。

supportFragmentManager.restoreBackStack("backstack1")

restoreBackStack にて保存しておいたBack stackが復元され、再び2番目のFragmentが表示されます。このとき EditText の入力状態なども復元されることになります。

例3

複数のBack stackを保存して、更にまとめて復元することもできます。

こちらも結果としては2番目と3番目が保存され、最初のFragmentが表示されることになります。

この状態から復元することもできます。

restoreBackStack を順番に呼び出すことで保存しておいたFragmentを再び表示することができます。

例4

BottomNavigationのような場合の切り替えをどのように実現するかを見てみます。

まずは最初の状態がこのようになっているとします。

次にBottomNavigationでの切り替えを行うとします。
まずはこれまで表示していたFragmentを保存して、その後に新しいFragmentを追加します。

さらに、この状態からBottomNavigationを切り替えて、前の状態に戻すときは以下のように保存と復元を行います。

結構ややこしい感じになってますが、これでBottomNavigationを切り替えても状態を残すようなことができます。

基本的に Navigation Component がやってくれる部分になれるので自分で実装する必要がないと思います。

実装時の注意

いくつか注意点があります。

setReorderingAllowed

必ず setReorderingAllowed(true) を実行するようにしてください。そうしないと saveBackStack 実行時にクラッシュします。

saveBackStack の順番

saveBackStack は一番上から順番にやっていく必要があります。そうしないと restoreBackStack でクラッシュすることがあります。

FragmentTransaction.commit 直後にsaveBackStack

以下のように、 commit 直後に saveBackStack を実行するとクラッシュしてしまいます。

これを回避するには、 saveBackStack 実行前に executePendingTransactions を実行して、FragmentTransactionの処理を完了させておく必要があります。

supportFragmentManager.executePendingTransactions()

--

--

Kenji Abe

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO