I am new to Dagger 2. I have 2 Activities, I want to use injected 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);
It is throwing an exception on inject:
java.lang.IllegalArgumentException: No injector factory bound for Class<com.mymart.ui.ProductListActivity>
Can anyone help me identify the problem in my code?
.......................................................................
Edit: I tried with ContributesAndroidInjector
as per @azizbekian, but it resulted following error on build:
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 changes, I am facing again exception: