画面遷移が得意なiOSでも画面間のデータの受け渡しは千差万別でした。いわんやAndroidもfragmentは歴史が浅いのか四苦八苦しました。
調べたところ、3つほど方法がみつかりました。
いったいどれを使うのが良いのか検討してみました。かなり独断と偏見なので、詳細は今後調べる必要があるかと思います。
ActivityModels
kotlinの開発案件で使われているソースを見かけます。
ViewModelを共有できるので便利ですが、その名の通りActivityを取得した共有であることに注意が必要です。
ViewModelを共有するので、任意のデータを共有するだけでなく、ロジックも共有したい場合に便利そうです。
Fragment KTXと呼ばれる拡張モジュールによって簡単に提供されてるので、次のように宣言するだけで共有されるためわかりやすいです。
class Fragment : Fragment() {
private val viewModel : ViewModel by activityViewModels()
}
setFragmentResult
FragmentManagerによるFragment間のデータの受け渡しを提供する機能のようです。
あるフラグメントの結果データを使いたい場合に便利かと思います。
ただ複数データの場合Bundleのため、変換実装が必要になることが想像しえます。
こちらもFragment KTXと呼ばれる拡張モジュールによって提供されています。
// 受け側Fragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setResultListener("Result") { key, bundle ->
val resultValue = bundle.getString("key")
}
}
// 送り側Fragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
button.setOnClickListener {
setResult("Result", bundleOf("key" to "result value"))
}
}
BackStackEntry
NavControllerに提供されるデータ受け渡しの機能のため、NavControllerを使っている場合はこちらを使うことになるかと思います。
currentBackStackEntryとpreviousBackStackEntryを使います。
使い方はsetFragmentResultsと似てますが、Mapで返却できたのでBundleよりは扱いやすいかなと感じました。
// 受け側Fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<String>("result")
?.observe(viewLifecycleOwner) {
}
}
// 送り側Fragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
button.setOnClickListener {
findNavController().previousBackStackEntry?.savedStateHandle?.set("result", "ABC")
findNavController().popBackStack()
}
}
データを1回だけ受け取る場合は受け取り後にremoveする必要があります。
結論
Fragment間でロジックを共有する場合はactivityModelsを利用して、データの受け取りだけであればNavControllerを使っていればBackStackEntry、使っていなければFragmentManagerのsetFragmentResultを使えばよいのかなといまいまは考えております。
何かご助言いただけれる場合はご連絡いただけますと幸いです。