Search code examples
androiddagger-2android-viewmodel

dagger 2 viewmodels and ViewModelProvider.Factory


Recently I had problems with a ViewModelProvider.Factory due to it was not loading all ViewModels of the project.

I have Activities and fragments. The activity ones are loaded without any problem, however I've tried to encapsulate FragmentViewModels inside the module where I'm creating the Fragment.

a bit of code:

@Module(includes = [
  ... ,... ,...
])
class UIModule {

    @Singleton
    @Provides
    fun provideViewModelFactory(viewModels: MutableMap<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>)
        : ViewModelProvider.Factory {

        return object : ViewModelProvider.Factory {

            override fun <T : ViewModel> create(modelClass: Class<T>): T {
                return requireNotNull(viewModels[modelClass]).get() as T
            }
        }
    } 
}

Activity Builder

@Module
abstract class MainActivityBuilder {
....

@ActivityScope
@ContributesAndroidInjector(modules [XXXFragmentModule::class])
abstract fun bindBottomNavigationActivity(): BottomNavigationActivity

}

so this is the XXXFragmentModule

@Module(includes = [ActividadesFragmentModule.ViewModule::class])
abstract class ActividadesFragmentModule {

  ....

    @ContributesAndroidInjector
    internal abstract fun contributeSuggestedFragment(): SuggestedFragment


    @Module
    abstract class ViewModule {

        @Binds
        @IntoMap
        @ViewModelKey(SuggestedViewModel::class)
        internal abstract fun bindSuggestedViewModel(viewModel: SuggestedViewModel): ViewModel
    }
}

this does not work, the viewModels of the first block of code does only have the ViewModels of the activities, it does not add this last ViewModel. However if the @Module(includes = [ActividadesFragmentModule.ViewModule::class]) is done in ActivityBuilder it does work perfeclty

@Module(includes = [ActividadesFragmentModule.ViewModule::class])
abstract class MainActivityBuilder 

does someone know what I am doing wrong?


Solution

  • You need to remove the scope from your ViewModelProvider.Factory

    @Singleton will never ever get anything from your Activity or Fragment scope. By removing the scope you create a new factory within every component—where it can collect the additional bindings that you added in those lower scopes.

    The factory itself is pretty lightweight so there should be no issues if it remains unscoped and gets recreated. @Reusable "scope" should work as well.