🍋

【Android】ダイアログの呼び出しをシンプルに記述する方法:Result API周りを呼び出し先に隠蔽する

2024/01/08に公開

概要

Android開発では、FragmentからDialogを呼び出し、Dialogが閉じた後にFragmentに通知するケースがよくあります。
この記事では、その処理を簡潔に行う方法を紹介します。
Fragment間の通信にはFragment Result APIを使用します。

元の実装

呼び出し元

呼び出し元のFragmentで、childFragmentManagerにリスナーを設定し、Dialogを表示します。

Fragment
childFragmentManager.setFragmentResultListener(
    DialogFragment.REQUEST_KEY,
    viewLifecycleOwner
) { requestKey: String, bundle: Bundle ->
    // Dialogが閉じたときの処理
    val result = bundle.getParcerable<DialogFragment(DialogFragment.BUNDLE_KEY)
    ..
}

DialogFragment.newInstance().show(childFragmentManager, DialogFragment.TAG)

呼び出し先

呼び出し先のDialogで、setFragmentResultに返したい値を渡します。
(以下は、ダイアログが閉じたことだけを通知する場合の実装例です)

DialogFragment
parentFragmentManager.setFragmentResult(
    REQUEST_KEY,
    bundleOf(BUNDLE_KEY to "")
)
dismiss()

改善後の実装

先述のとおり、今回はダイアログが閉じたことだけを呼び出し元のFragmentに通知するとします。
そこでFragment Result API周りの処理をDialogFragment側に隠蔽し、ラムダでコールバックする実装にしました。
resultではなくdismissそのものを通知するイメージです。

呼び出し元

Fragment側でDialogを呼び出す処理はこれだけになります。

Fragment
DialogFragment.newInstance().show(
    targetFragment = this,
    onDismissDialog = {
        // Dialogが閉じたときの処理
    }
)

呼び出し先

DialogFragmentの実装は以下の通りです。

DialogFragment
fun show(targetFragment: Fragment, onDismissDialog: () -> Unit) {
    targetFragment.childFragmentManager.setFragmentResultListener(
        REQUEST_KEY,
        targetFragment.viewLifecycleOwner
    ) { requestKey: String, bundle: Bundle ->
        if (bundle.containsKey(BUNDLE_KEY)) {
	    onDimissDialog()
	}
    }
    
    show(targetFragment.childFragmentManager, TAG)
}

override fun onDismiss(dialog: DialogInterface) {
    super.onDismiss(dialog)
    
    parentFragmentManager.setFragmentResult(
        REQUEST_KEY, bundleOf(BUNDLE_KEY "")
    )
}

呼び出し元の実装がシンプルになりました🎉

参考

https://developer.android.com/guide/fragments/communicate?hl=ja#fragment-result

https://qiita.com/TomAndDev/items/a7444d3ac6ef9d2d3ad4

Discussion