MVVMパターンにおいてFragment間でデータを共有するには、ViewModelを使うのがよいとされています。ViewModelのインスタンスを複数のFragmentに挿入するには、KoinのsharedViewModel()を使うと便利です。
しかし、普通にsharedViewModel()を使うと、ViewModelOwnerはActivityになります。これで問題がなければ構わないのですが、Navigation ComponentのSingle Activityアーキテクチャを使っている場合など、各FragmentのViewModelがすべて一つのActivityに紐づいてしまうと困る場合もあります。
そこで、KoinのsharedViewModel()で、特定のFragmentをOwnerに指定しつつ別のFragmentにも同じインスタンスを挿入する方法を紹介します。
(注)Koinのバージョンは2.2.2で確認しています。比較的最近追加された機能ですので、古いバージョンでは動作しない可能性があります。
import org.koin.android.viewmodel.ViewModelOwner.Companion.from
import org.koin.android.viewmodel.ext.android.sharedViewModel
// 親フラグメント
class MainFragment: Fragment() {
private val viewModel: SampleViewModel by sharedViewModel(owner = { from(this) })
}
// 子フラグメント
class SubFragment: Fragment() {
private val viewModel: SampleViewModel by sharedViewModel(owner = { from(requireParentFragment()) })
}SubFragmentはMainFragmentの子供として配置されているものとします。MainFragmentではthisを、SubFragmentではrequireParentFragment()をsharedViewModel()のowner引数に与えることで、MainFragmentをOwnerとする共通のViewModelインスタンスを挿入することができます。
これで、MainFragmentが作成されるたびにSampleViewModelのインスタンスが作成され、なおかつSubFragmentからはMainFragmentと同じSampleViewModelのインスタンスにアクセスすることができます。
module宣言は通常通りviewModelを宣言すればOKです。
@JvmField
val appModlue = module {
viewModel { SampleViewModel() }
}moduleの宣言には特に手を加えず、挿入する側で挿入方法を柔軟に設定できるあたり、Koinは本当によくできてるなと感じます。公式の説明は下記にあります。もう少し具体的に書いてくれていると助かるんですけどね・・・。ってあれ?サイトのデザインがきれいになってる!


