🦔

【Android】setFragmentResult の結果を Fragment で受け取る

2021/08/26に公開

setFragmentResult / setFragmentResultListener を使用する

setFragmentResultsetFragmentResultListenerを使って結果の受け渡しを行うのですが、これらを使えるようにするために、app/build.gradleに依存関係を追加します。

app/build.gradle

dependencies {
    // 追加
    implementation "androidx.fragment:fragment-ktx:1.3.6"
}

結果の受け渡し

setFragmentResultListener

  • 第1引数 : 結果を渡す際に使用するrequestKeyを設定
  • 第2引数 : ライフサイクルを指定

このライフサイクルがLifecycle.State.STARTEDの状態になると、setFragmentResultで設定した結果が配信されます。

childFragmentManager.setFragmentResultListener(
    "request_key",
    viewLifecycleOwner
) { requestKey: String, result: Bundle ->
    val text = result.getString("key_text", "")
    ...
}

setFragmentResult

  • 第1引数 : 結果を渡す際に使用するrequestKeyを設定
  • 第2引数 : 渡したい結果をセットしたBundleを指定
val bundle = bundleOf("key_text" to "sample")
setFragmentResult("request_key", bundle)

FragmentManager について

ActivityFragment間で結果をやりとりする場合はsupportFragmentManagerFragmentFragment間の場合はchildFragmentManagerを使います。

Activity と Fragment 間で結果を渡す場合

親Fragment と 子Fragment 間で結果を渡す場合

実装例 : DialogFragment(子Fragment)の結果を親Fragment で受け取る

MainActivity.kt

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        supportFragmentManager.beginTransaction()
            .replace(R.id.content_layout, MainFragment.newInstance())
            .commitNow()
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/content_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" />

MainFragment.kt

class MainFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = inflater.inflate(R.layout.fragment_main, container, false)

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        childFragmentManager.setFragmentResultListener(
            REQUEST_KEY,
            viewLifecycleOwner
        ) { _, result: Bundle ->
            val text = result.getString(MyDialog.KEY_CLICK, "unknown")
            Toast.makeText(requireActivity(), text, Toast.LENGTH_SHORT).show()
        }

        requireActivity().findViewById<Button>(R.id.show_dialog_button).setOnClickListener {
            MyDialog.newInstance(
                requestKey = REQUEST_KEY
            ).show(childFragmentManager, this::class.java.simpleName)
        }
    }

    companion object {
        fun newInstance() = MainFragment()
        private const val REQUEST_KEY = "request_key"
    }
}

fragment_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/show_dialog_button"
        style="@style/Widget.MaterialComponents.Button"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:layout_marginStart="10dp"
        android:layout_marginEnd="10dp"
        android:text="ダイアログを表示する"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

MyDialog.kt

class MyDialog : DialogFragment() {

    private val _requestKey: String
        get() = requireArguments().getString(KEY_REQUEST, "")

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        return AlertDialog.Builder(requireActivity()).apply {
            setTitle("タイトル")
            setMessage("クリックイベントを伝えるよ")
            setPositiveButton("ok") { _, _ ->
                val bundle = bundleOf(KEY_CLICK to "okをクリック")
                setFragmentResult(_requestKey, bundle)
            }
            setNegativeButton("cancel") { _, _ ->
                val bundle = bundleOf(KEY_CLICK to "cancelをクリック")
                setFragmentResult(_requestKey, bundle)
            }
        }.create()
    }

    companion object {
        fun newInstance(
            requestKey: String
        ) = MyDialog().apply {
            arguments = bundleOf(KEY_REQUEST to requestKey)
        }

        const val KEY_CLICK = "click"
        private const val KEY_REQUEST = "key_request"
    }
}

Discussion