Fragment Result APIを使ってFragment同士でデータを送る/受取る

2022-10-15

はじめに

Android 開発をする上で Fragment 同士でデータのやり取りをしたいことはよくあります。ViewModel を共有する方法Safe args を使う方法などなど…色々ある中で今回は、Fragment Result APIを使って送る/受取るというものを試してみます。Fragment Result APIにしたのは業務で使ったためですが、具体的な理由として以下のような状況だったためです。

  • ViewModel を書くほどでもない Fragment(DialogFragment を継承した OK ボタンが一つあるだけのオリジナルの Dialog)で使いたい
    • 一つの Fragment に対して一つの ViewModel を書くというのは強制でやったほうがよかったなと今になって思います…
  • Navigation Component を導入してないプロジェクトで、Safe args のために入れるのは大げさ
    • Navigation Component は入れたほうがいいのは間違いないのでやっぱり今後のことを考えてこっちにしとけばよかった…

技術選定って難しいですね…

今回は、Fragment から DialogFragment を呼び出し、DialogFragmentのボタンをタップしたら 0 から 100 までのいずれかの Int を生成します。生成後、呼び出し元の Fragment に渡し、Snackbar で表示します。実際のコードは、このリポジトリに置いています。(お触りのために Navigation Component や View Binding を使いたかったので、そっちも入ってます)

実際にビルドするとこんな感じです。

実行した画面のgif画像

実装

Fragment Result APIを使うためにfragment-ktxライブラリを入れます。

app.build.gradle
dependencies {
        implementation 'androidx.fragment:fragment-ktx:1.5.3'}

呼び出し元の Fragment のコードです。省略していますが、View Bindingを使っています。Data Binding ではなく View Binding を使った理由は UI に対して何かしらの変更を加えることはしない(双方向である必要がない)ので View Binding しました。詳細はリポジトリのコードをご参照下さい。

setFragmentResultListenerを使ってリスナーを登録し、データが来るのを待っています。

Fragment1.kt
class Fragment1 : Fragment() {
    // 省略

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // 省略
        // ここで値を受取る
        setFragmentResultListener(CustomFragmentDialog.requestKey) { _, bundle ->            val receiveInt = bundle.getInt(CustomFragmentDialog.bundleKey, -1)
            Snackbar.make(
                requireActivity().findViewById(R.id.activity_main),
                receiveInt.toString(),
                Snackbar.LENGTH_LONG
            ).show()

        }

        // 省略
    }
    // 省略
}

送信側(DialogFragment を継承したオリジナルの Dialog)のコードです。setFragmentResultでデータを格納しています。また、データをやり取りをするために必要な Key を、static にして簡単に呼び出せるようにしています。

Fragment1.kt
class CustomFragmentDialog : DialogFragment() {

    private var _binding: FragmentCustomDialogBinding? = null
    private val binding get() = _binding!!

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        super.onCreateDialog(savedInstanceState)
        // 省略
        val dialog = Dialog(requireActivity())
        binding.doneButton.setOnClickListener {
            val randomInt = (0..100).random()
            val bundle = bundleOf(bundleKey to randomInt)            // ここでデータを渡します            setFragmentResult(requestKey, bundle)            dismiss()
        }
        return dialog
    }

    companion object {
        const val bundleKey = "customFragmentDialogBundleKey"
        const val requestKey = "customFragmentDialogRequestKey"
    }
}

最後に

今回は、Fragment Result APIを使って Fragment 同士でデータのやり取りをする方法について書きました。改めて調べ直すと Fragment 同士のデータの受け渡しは、色々な実装方法があるんだなと思いました。そして、技術選定の難しさを体感しました…

あと、Navigation Component の勉強せねばーとなりました。やるぞー。

参考サイト

Tatsumi0000

Written by Tatsumi0000 モバイル開発が好きなエンジニアのブログです. GitHub

Copyright © 2023, Tatsumi0000 All Rights Reserved.