LoginSignup
4
1

More than 3 years have passed since last update.

setFragmentResultListenerを使った通知をするDialogFragmentの実装提案

Last updated at Posted at 2020-08-12

androidx.fragment:fragment:1.3.0-alpha04から新しく setFragmentResult / setFragmentResultListenerが追加され、setTargetFragmentがdeprecatedになりました。

おそらく多くの呼び出し元に通知を送るDialogFragmentでは、setTargetFragmentを使ってListenerなどで実装していたのではないでしょうか。

従来のDialogFragment.kt
class MyDialogFragment : DialogFragment() {

    companion object {
        private const val REQUEST_CODE = 100

        fun show(target: Fragment) =
            newInstance().run {
                setTargetFragment(target, REQUEST_CODE)
                show(target.requireFragmentManager(), "MyDialogFragment")
            }

        private fun newInstance() = MyDialogFragment()
    }

    private lateinit var listener: MyListener

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        listener = targetFragment as? MyListener
            ?: throw IllegalArgumentException("This targetFragment is not `MyListener`")
    }
・・・
・・・
・・・
    interface MyListener {
        fun onClickHoge()
        fun onDismiss()
    }
}

だいたいこんな感じかと思うんですが、
もちろんsetTargetFragmentrequireFragmentManagerも使えないので、
以下のような感じにすると、これまでの使用感をあまり変えずに、実装できるのではないでしょうか。

提案するDialogFragment.kt
class MyDialogFragment : DialogFragment() {

    companion object {
        private const val REQUEST_KEY = "request_key_my_dialog"
        private const val RESULT_KEY_HOGE = "result_key_hoge_my_dialog"
        private const val RESULT_KEY_DISMISS = "result_key_dismiss_my_dialog"

        fun show(
            target: Fragment,
            onClickHoge: (() -> Unit)? = null,
            onDismiss: (() -> Unit)? = null
        ) {
            newInstance().run {
                target
                    .childFragmentManager
                    .setFragmentResultListener(REQUEST_KEY, target.viewLifecycleOwner) { requestKey, bundle ->
                        if (requestKey != REQUEST_KEY) return@setFragmentResultListener
                        when {
                            bundle.containsKey(RESULT_KEY_HOGE) -> onClickHoge?.invoke()
                            bundle.containsKey(RESULT_KEY_DISMISS) -> onDismiss?.invoke()
                        }
                    }
                show(target.childFragmentManager, "MyDialogFragment")
            }
        }

        private fun newInstance() = MyDialogFragment()
    }

まず、setFragmentResultListenerにすることで、カスタムリスナーは必要なくなり、
onAttachでの処理も全て必要なくなります。

ちなみに結果を通知する際は、例に倣って以下のように行います

// 通知したい場所で
setFragmentResult(REQUEST_KEY, bundleOf(RESULT_KEY_DISMISS to ""))

従来のDialogFragmentを使用する場合は、

// Fragmentで呼ぶ場合を想定
MyDialog.show(this)

こんな感じでshowして、通知に関しては、Fragmentにリスナーを実装していたと思いますが、

MyDialog.show(
    target = this,
    onClickHoge = {
        // Hogeの処理
    },
    onDismiss = {
        // Dismissの処理
    }
)

といった感じで、ラムダを使用して、カスタムリスナーを使用しなくても、
通知を実装することができ、とてもシンプルになります。

いかがでしょうか?
何かもう少しこうしたら良いなど、ご意見あればお願いいたします。

参考:
setFragmentResultを使ったFragment間のデータ受け渡し
フラグメント間でデータを渡す

4
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1