6
6

More than 3 years have passed since last update.

【Kotlin】setFragmentResultを用いた画面遷移

Posted at

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を記述する必要がなくなり、バグが発生する可能性を低くすることができます。

6
6
0

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
6
6