ViewModelOwnerをFragmentに設定し、子Fragmentとデータを共有する
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.fromimport 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です。
@JvmFieldval appModlue = module { viewModel { SampleViewModel() }}moduleの宣言には特に手を加えず、挿入する側で挿入方法を柔軟に設定できるあたり、Koinは本当によくできてるなと感じます。公式の説明は下記にあります。もう少し具体的に書いてくれていると助かるんですけどね・・・。ってあれ?サイトのデザインがきれいになってる!