おさらい
- Fragmentの戻るボタン処理についてのお話。
AppCompatActivity.onBackPressed()をオーバーライドしてごちゃごちゃやるよりはAppCompatActivity.onBackPressedDispatcher.addCallback()を使うのがナウい。addCallback(owner: lifecycleOwner,...)は最後に追加されたものでかつ有効なものだけが処理される。AppCompatActivity.onBackPressed()の中でonBackPressedDisptacher.onBackPressed()を呼ぶようになっているので、自前のActivityでオーバーライドした場合その中でsuper.onBackPressed()を呼ばないとコールバックは全て無視される。
問題
addCallback(owner: lifecycleOwner,...)は最後に追加されたものでかつ有効なものだけが処理される。
- Activity側の
onCreate()内でActivityの戻るボタン処理をaddCallback()する。 onCreate()内でFragmentを作成してsupportFragmentManagerにaddする。- Fragment側では
onCreateView()内でFragmentの戻るボタン処理をaddCallback()する。
という3ステップを踏んだ場合、どうも戻るボタンコールバックのスタックに積まれる順番は想定していた 1:Activity → 2:Fragment ではなく、1:Fragment → 2:Activity になる。
原因
公式リファレンス / OnBackPressedDispatcher には次のように記述がある。
Receive callbacks to a new OnBackPressedCallback when the given LifecycleOwner is at least started.
onStart()が呼ばれる順番は 1:Activity → 2:Fragment じゃなかったかしらと思ったら、
LifecyclerStateがSTARTEDになるのはonStart()が呼ばれたときではなく抜けたときなのであった。
STARTED
Started state for a LifecycleOwner. For an Activity, this state is reached in two cases:
- after onStart call;
- right before onPause call.
Activity.onStart()内でFragment.onStart()が呼ばれるので、つまりLifecycle.StateがSTARTEDになる順番は 1:Fragment → 2:Activity となる。
戻るボタンコールバックはSTARTEDになった順に積まれるので、Fragment.onCreateView()とかでコールバックを追加するとActivityのコールバックの方が後に積まれることになり、結果的にFragmentのコールバックが無視されたような動作になる。
解決
というわけで、Activity.onStart()が完了する前にFragmentを作成してアタッチする場合、Fragment側のコールバックを登録するコードはFragment.onResume()~のタイミングで行うようにしましょうということらしい。