Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?
@TomAndDev

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

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間のデータ受け渡し
フラグメント間でデータを渡す

1
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
1
Help us understand the problem. What is going on with this article?