この内容は技術書典7で頒布予定の Master of Dagger(仮)の正式版にも掲載予定です。
ここには詳しい解説は書かないので、ぜひ Master of Dagger(仮)の正式版を買ってください。
0.
このような ViewModel があります。(Dagger で生成させてる MainViewModel のコンストラクタに SavedStateHandle を追加した)- class MainViewModel @Inject constructor(
- private val api: MyApi,
- private val handle: SavedStateHandle
- ) : ViewModel() {
- ...
- }
- @Module
- class AppModule {
- @Singleton
- @Provides
- fun provideApi(): MyApi {
- return ...
- }
- }
- @Module
- interface BindModule {
- @Binds
- @IntoMap
- @ViewModelKey(MainViewModel::class)
- fun bindMainViewModel(viewModel: MainViewModel): ViewModel
- }
1.
SavedStateHandle をオブジェクトグラフに含む Subcomponent を用意します。- @Module(subcomponents = [SavedStateViewModelComponent::class])
- class SavedStateViewModelComponentModule
- @Subcomponent
- interface SavedStateViewModelComponent {
- @Subcomponent.Factory
- interface Factory {
- fun create(
- @BindsInstance handle: SavedStateHandle
- ): SavedStateViewModelComponent
- }
- fun providers(): Map<Class<out ViewModel>, Provider<ViewModel>>
- }
2.
次に AbstractSavedStateViewModelFactory を継承した Factory を用意します。ポイントはコンストラクタで先ほど作った SavedStateViewModelComponent.Factory を受け取るようにし、create() でそれを利用して ViewModel の Map Multibindings を受け取るようにすることです。
- class SavedStateViewModelFactory @Inject constructor(
- private val factory: SavedStateViewModelComponent.Factory,
- owner: SavedStateRegistryOwner,
- defaultArgs: Bundle? = null
- ) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
- override fun <T : ViewModel?> create(
- key: String,
- modelClass: Class<T>,
- handle: SavedStateHandle
- ): T {
- val providers = factory.create(handle).providers()
- val found = providers.entries.find { modelClass.isAssignableFrom(it.key) }
- val provider = found?.value
- ?: throw IllegalArgumentException("unknown model class $modelClass")
- try {
- @Suppress("UNCHECKED_CAST")
- return provider.get() as T
- } catch (e: Exception) {
- throw RuntimeException(e)
- }
- }
- }
3.
SavedStateRegistryOwner と Bundle? をオブジェクトグラフに含む Subcomponent を用意します。SavedStateComponent の modules に SavedStateViewModelComponentModule を指定します。
- @Module(subcomponents = [SavedStateComponent::class])
- class SavedStateComponentModule
- @Subcomponent(modules = [SavedStateViewModelComponentModule::class])
- interface SavedStateComponent {
- @Subcomponent.Factory
- interface Factory {
- fun create(
- @BindsInstance owner: SavedStateRegistryOwner,
- @BindsInstance defaultArgs: Bundle?
- ): SavedStateComponent
- }
- fun viewModelFactory(): SavedStateViewModelFactory
- }
4.
AppComponent の modules に SavedStateComponentModule を指定します。- @Singleton
- @Component(
- modules = [
- AppModule::class,
- BindModule::class,
- SavedStateComponentModule::class
- ]
- )
- interface AppComponent {
- fun savedStateComponentFactory(): SavedStateComponent.Factory
- }
5.
SavedStateComponentから取得したFactoryを使います。- class MainActivity : AppCompatActivity() {
- private val viewModel: MainViewModel by viewModels {
- (application as MyApplication).appComponent
- .savedStateComponentFactory()
- .create(this, null)
- .viewModelFactory()
- }
- ...
- }
0 件のコメント:
コメントを投稿