Dagger: IllegalArgumentException: no factory injector for class

I am new to dagger 2. I have 2 actions, I want to use the nested ViewModel for both. Here is my ViewModuleFactory :

@Singleton public class ProductViewModelFactory implements ViewModelProvider.Factory { private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators; @Inject public ProductViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) { this.creators = creators; } @SuppressWarnings("unchecked") @Override public <T extends ViewModel> T create(Class<T> modelClass) { Provider<? extends ViewModel> creator = creators.get(modelClass); if (creator == null) { for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) { if (modelClass.isAssignableFrom(entry.getKey())) { creator = entry.getValue(); break; } } } if (creator == null) { throw new IllegalArgumentException("unknown viewmodel class " + modelClass); } try { return (T) creator.get(); } catch (Exception e) { throw new RuntimeException(e); } } } 

My ViewModelModule :

 @Module abstract class ViewModelModule { @Binds @IntoMap @ViewModelKey(ProductListViewModel.class) abstract ViewModel bindProductListViewModel(ProductListViewModel listViewModel); @Binds @IntoMap @ViewModelKey(ProductDetailsViewModel.class) abstract ViewModel bindProductDetailsViewModel(ProductDetailsViewModel detailsViewModel); @Binds abstract ViewModelProvider.Factory bindViewModelFactory(ProductViewModelFactory factory); } 

My ViewModelKey for mapping:

 @Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @MapKey @interface ViewModelKey { Class<? extends ViewModel> value(); } 

My ActivityModule :

 @Module public abstract class ActivityModule { abstract ProductListActivity contributeProductListActivity(); abstract ProductDetailsActivity contributeProductDetailsActivity(); } 

My AppModule :

 @Module class AppModule { @Provides @Singleton RedMartProductService provideRedMartProductService() { ........ } @Provides @Singleton ProductListRepository provideProductListRepository(ProductListRepository repository) { return repository; } @Provides @Singleton ProductDetailsRepository provideProductDetailsRepository(ProductDetailsRepository repository) { return repository; } } 

My AppComponent :

 @Singleton @Component(modules = {AndroidInjectionModule.class, ActivityModule.class, AppModule.class}) public interface AppComponent { @Component.Builder interface Builder { @BindsInstance Builder application(Application application); AppComponent build(); } void inject(MartApplication martApp); } 

My Application :

 public class MartApplication extends Application implements HasActivityInjector { @Inject DispatchingAndroidInjector<Activity> dispatchingAndroidInjector; @Override public void onCreate() { super.onCreate(); } @Override public DispatchingAndroidInjector<Activity> activityInjector() { return dispatchingAndroidInjector; } } 

In Activity :

 @Inject ViewModelProvider.Factory viewModelFactory; ....... AndroidInjection.inject(activity); // Throwing exception ListViewModel = ViewModelProviders.of(this, viewModelFactory).get(ProductListViewModel.class); 

Throws an exception on injection:

 java.lang.IllegalArgumentException: No injector factory bound for Class<com.mymart.ui.ProductListActivity> 

Can someone help me identify a problem in my code?

.................................................. .....................

Edit : I tried with ContributesAndroidInjector according to @azizbekian, but this led to an error during assembly:

  error: [dagger.android.AndroidInjector.inject(T)] Found a dependency cycle: com.mymart.repository.ProductListRepository is injected at com.mymart.di.AppModule.provideProductListRepository(repository) com.mymart.repository.ProductListRepository is injected at com.mymart.viewmodel.ProductListViewModel.<init>(productListRepository) com.mymart.viewmodel.ProductListViewModel is injected at com.mymart.di.ViewModelModule.bindProductListViewModel(listViewModel) java.util.Map<java.lang.Class<? extends android.arch.lifecycle.ViewModel>,javax.inject.Provider<android.arch.lifecycle.ViewModel>> is injected at com.mymart.viewmodel.ProductViewModelFactory.<init>(creators) com.mymart.viewmodel.ProductViewModelFactory is injected at com.mymart.di.ViewModelModule.bindViewModelFactory(factory) android.arch.lifecycle.ViewModelProvider.Factory is injected at com.mymart.ui.ProductListActivity.viewModelFactory com.mymart.ui.ProductListActivity is injected at dagger.android.AndroidInjector.inject(arg0) 

Edit 2 After all the changes, I again encounter the exception:

 java.lang.RuntimeException: Unable to create application com.kaushik.myredmart.MartApplication: java.lang.IllegalStateException: com.kaushik.myredmart.di.AppModule must be set at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4710) at android.app.ActivityThread.-wrap1(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by: java.lang.IllegalStateException: com.kaushik.myredmart.di.AppModule must be set at com.kaushik.myredmart.di.DaggerAppComponent$Builder.build(DaggerAppComponent.java:180) at com.kaushik.myredmart.di.AppInjector.init(AppInjector.java:30) at com.kaushik.myredmart.MartApplication.onCreate(MartApplication.java:28) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1013) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4707) at android.app.ActivityThread.-wrap1(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1405) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke(Native Method) 
+7
android dependency-injection dagger dagger-2
source share
2 answers

I believe that you forgot to add the @ContributesAndroidInjector annotation:

 @Module public abstract class ActivityModule { @ContributesAndroidInjector abstract ProductListActivity contributeProductListActivity(); @ContributesAndroidInjector abstract ProductDetailsActivity contributeProductDetailsActivity(); }
@Module public abstract class ActivityModule { @ContributesAndroidInjector abstract ProductListActivity contributeProductListActivity(); @ContributesAndroidInjector abstract ProductDetailsActivity contributeProductDetailsActivity(); } 

And enable ViewModelModule in the AppModule :

 @Module(includes = ViewModelModule.class) class AppModule { ... }
@Module(includes = ViewModelModule.class) class AppModule { ... } 

See this code you wrote:

 @Provides @Singleton ProductListRepository provideProductListRepository(ProductListRepository repository) { return repository; } 

What do you expect? You tell the dagger "hey, dagger, whenever I ask you to provide me with a ProductListRepository , then create (return) this object using ProductListRepository ." It will not work.

Most likely, what you intended was β€œhey dagger” when I ask you to provide me with an implementation of ProductListRepository , and then create (return) this object using ProductListRepositoryImpl ":

 @Provides @Singleton ProductListRepository provideProductListRepository(ProductListRepositoryImpl repository) { return repository; } 

Which can be replaced by the following:

 @Binds @Singleton abstract ProductListRepository provideProductListRepository(ProductListRepositoryImpl repository); 
+10
source share

Using @contrubutesAndroidInjector requires an additional annotation processor.

Add this line to the gradle assembly file:

 annotationProcessor 'com.google.dagger:dagger-android-processor:2.11' 
-4
source share

All Articles