おさらい
- 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()
~のタイミングで行うようにしましょうということらしい。