setFragmentResultとは
フラグメント間でデータの受け渡しを行うときに使用する。
フラグメントBからフラグメントAにデータを返す場合は、フラグメントAに結果リスナーを設定します。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Use the Kotlin extension in the fragment-ktx artifact
setResultListener("requestKey") { key, bundle ->
// We use a String here, but any type that can be put in a Bundle is supported
val result = bundle.getString("bundleKey")
// Do something with the result...
}
}
フラグメントBでは、同じrequestKey
を使用して値を渡します。
button.setOnClickListener {
val result = "result"
// Use the Kotlin extension in the fragment-ktx artifact
setResult("requestKey", bundleOf("bundleKey" to result))
}
複数のデータをまとめて渡す場合
調べても複数のデータをまとめてsetFragmentResult
で渡す実装が出てこなかったため以下に記載しておきます。
例えば、ユーザー一覧画面でユーザーを選択すると選択されたユーザーの編集画面に遷移する場合、画面の遷移時に複数のデータの受け渡しが必要になります。
data class user (
val id: Int,
val name: String,
val icon: String,
val registerDate: String
)
UserListFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setFragmentResult("request_key", bundleOf(
"id" to selectedUser.id
"name" to selectedUser.name
"icon" to selectedUser.icon
"registerDate" to selectedUser.registerDate
)
}
UserDetailFragment
setFragmentResultListener("request_key") { requestKey, bundle ->
val id = bundle.getInt("id")
val name = bundle.getString("name")
val icon = bundle.getString("icon")
val registerDate = bundle.getString("registerDate")
}
上記のように設定することで複数のデータをフラグメント間で扱うことができます。
しかし、このような実装だと、リテラルがバラバラなところに書いてあり、setFragmentResult
側とsetFragmentResultListener
側でキー名がずれたときに追跡しにくくバグの温床になります。
data classをまとめて受け渡す
UserDetailFragment
companion object {
const val REQ_KEY: String = "UserDetailFragment"
private const val ARG_USER: String = "user"
fun createArguments(user: User): Bundle {
return bundleOf(ARG_USER to user)
}
}
・
・
・
// 一覧画面から選択された値を取得
setFragmentResultListener(REQ_KEY) { _, bundle ->
// getSerializableによりUserデータをまとめて受け取ることができる
val user = bundle.getSerializable(ARG_USER) as User
id = user.id
name = user.name
・
・
・
}
UserListFragment
override fun onClickRow(tappedView: View, selectedUser: User) {
// 呼び出し側でBundleに入れるキー名を与えなくても済む
setFragmentResult(
UserDetailFragment.REQ_KEY,
UserDetailFragment.createArguments(selectedUser)
)
}
User
data class User(
val id: Int,
val name: String,
val icon: String,
val registerDate: String
): Serializable // BundleにはSerializeを入れることができるため追加
このコードで行ったこととしては
- ModelをSerializable化し、Userのデータをまとめて渡す。
-
createArguments
メソッドにより、呼び出し側でキー名を知る必要がなくなる。
このようにリファクタリングすることで複数箇所にRequestKey
を記述する必要がなくなり、バグが発生する可能性を低くすることができます。