Open4
[Android] 汎用的な DialogFragment にホストから動作を注入したい
目的
- 汎用的な DialogFragment にホストから動作を注入したい
- 削除確認等の DialogFragment を共通化したい
理想
// HostFragment
fun delete(id){
ConfirmDangerDialogFragment.newInstance(
title = "削除しますか?",
completion = {
viewModel.delete(id)
}
).show(childFragmentManager, ConfirmDangerDialogFragment::class.java.name)
}
問題点
Activity が破棄された場合、再生成のタイミングで completion の内容が失われる(クロージャは bundle に保存できない)
→ ダイアログの見た目は復元されるが、ボタンを押しても何も起こらない
解決策1
呼び出し元の Activity(Fragment) にリスナーを implements する
問題点
- onAttach で復元する関係上、無名クラスで渡すことができない
- ソースコードが散らばってしまい、処理の流れを追いにくい
- 呼び出し側が送ったパラメータ(削除するもの)を意識する必要があるため、ダイアログの汎用性が損なわれる(「〇〇を削除するためのダイアログ」というのをダイアログ側が意識する必要がある)
解決策2
setFragmentResultListener を利用する
実装例
Fragment のインスタンス生成時に setFragmentResultListener を行なっている
問題点
- Activity が破棄されると listener が破棄されるので、イベントがトリガーされない
- 加えて、二回目にダイアログを開いたタイミング(setFragmentResultListener したタイミング)でイベントが発火してしまう
- → setFragmentResultListener は onCreate で呼び出す必要がある
- 解決策1と同じ問題に直面する
解決策3
中途半端に再生成されるのが問題なので、 Activity が再生成された場合に Dialog を復元しないようにする
// DialogFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null){
dismiss()
}
}
問題点
- 一般的なフラグメントのライフサイクルに沿っていない
- 画面回転でダイアログが消えてしまう(実装中のアプリは縦画面固定なのでここは問題なさそう?)
- 再生成が起きるタイミングはこちらでは制御できないため、意図しないタイミングでダイアログが消える可能性がある。