Reputation: 617
I am learning dagger dependency injection(I know i am late to the party, its better to start now).
But I am facing below error. Please any help or suggestion could be greatly appreciated.
ERROR Log
error: [Dagger/MissingBinding] [dagger.android.AndroidInjector.inject(T)] @com.mypackage.di.key.ItemDetail java.lang.Integer cannot be provided without an @Provides-annotated method.
public interface ApplicationComponent extends AndroidInjector<RetailShopApplication> {
^
@com.mypackage.di.key.ItemDetail java.lang.Integer is injected at
com.mypackage.ui.detail.ItemDetailViewModel.<init>(…, itemId)
com.mypackage.ui.detail.ItemDetailViewModel is injected at
com.mypackage.di.module.ViewModelModule.provideItemDetailViewModel(itemDetailViewModel)
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
com.mypackage.viewModel.ViewModelFactory.<init>(creators)
com.mypackage.viewModel.ViewModelFactory is injected at
com.mypackage.ui.home.ItemCategoryFragment.itemViewFactory
com.mypackage.ui.home.ItemCategoryFragment is injected at
dagger.android.AndroidInjector.inject(T)
component path: com.mypackage.di.component.ApplicationComponent ? com.mypackage.di.builder.ActivityBuilder_ContributeHomeActivity.HomeActivitySubcomponent ? com.mypackage.ui.home.HomeFragmentProvider_ContributeItemCategoryFragment.ItemCategoryFragmentSubcomponent
My Problem
I created a provideItemDetailViewModel() with contributeAndroidInjection annotation in ViewModelModule but the ItemDetailViewModel contructor has an integer value.
So i am providing an integer value at runtime from my activity intent through ItemDetailActivityModule class. Problem is dagger throwing me an error "integer already exist in the scope" but not able to inject in the ViewModel contructor.
ViewModelModule
@Module
public abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(ItemCategoryViewModel.class)
abstract ViewModel provideItemCategoryViewModel(ItemCategoryViewModel
itemCategoryViewModel);
@Binds
@IntoMap//<---- Here is the new ViewModel
@ViewModelKey(ItemDetailViewModel.class)
abstract ViewModel provideItemDetailViewModel(ItemDetailViewModel
itemDetailViewModel);
@Binds
abstract ViewModelProvider.NewInstanceFactory
getViewModelFactory(ViewModelFactory viewModelFactory);
}
ItemDetailViewModel
@Inject
public ItemDetailViewModel(Application application, @ItemDetail int itemId)
{
itemRepository = new ItemRepository(application);
itemLiveData = itemRepository.getItem(itemId);
}
ItemDetailActivityModule
@Module
public class ItemDetailActivityModule {
@Provides
@ItemDetail
int provideItemId(ItemDetailActivity itemDetailActivity) {
return itemDetailActivity.getIntent().getIntExtra(AppConstants.ITEM_ID,
0);
}
}
ActivityBuilder
@Module
public abstract class ActivityBuilder {
@ActivityScope
@ContributesAndroidInjector(modules = {HomeFragmentProvider.class,
HomeActivityModule.class})
abstract HomeActivity contributeHomeActivity();
@ActivityScope
@ContributesAndroidInjector(modules = ItemDetailActivityModule.class)
abstract ItemDetailActivity contributeItemDetailActivity();
}
ApplicationComponent
@Singleton
@Component(modules = {AndroidSupportInjectionModule.class,
ApplicationModule.class, ActivityBuilder.class})
public interface ApplicationComponent extends
AndroidInjector<RetailShopApplication> {
@Component.Builder
abstract class Builder extends
AndroidInjector.Builder<RetailShopApplication> {
}
}
ApplicationModule
@Module(includes = ViewModelModule.class)
public class ApplicationModule {
@Provides
Application provideApplication(RetailShopApplication application) {
return application;
}
}
Upvotes: 1
Views: 1074
Reputation: 617
Problem is i was creating provider for each ViewModel in ViewModelModule class which is included in AppModule.
Every Activity created using @ContributeAndroidInjection is a sub component.
So App component and Activity sub component are different. Activity component can access provider of App component but its not vice versa that the reason for injection already exist error
I solved the problem my including view model inside the activity module instead of appcomponent module.
Before
@Module
public abstract class ViewModelModule {
@Binds
@IntoMap//<---- Here is the new ViewModel
@ViewModelKey(ItemDetailViewModel.class)
abstract ViewModel provideItemDetailViewModel(ItemDetailViewModel
itemDetailViewModel);
@Binds
abstract ViewModelProvider.NewInstanceFactory
getViewModelFactory(ViewModelFactory viewModelFactory);
}
After - Only ViewModelFactory is necessary in ViewModelModule move all your ViewModel provider to activity module.
@Module
public abstract class ViewModelModule {
@Binds
abstract ViewModelProvider.NewInstanceFactory
getViewModelFactory(ViewModelFactory viewModelFactory);
}
Create Abstract class in order to hold the ViewModel providers
@Module
public abstract class ItemDetailProvider {
@Binds
@IntoMap
@ViewModelKey(ItemDetailViewModel.class)
abstract ViewModel provideItemDetailViewModel(ItemDetailViewModel
itemDetailViewModel);
}
Now add the created provider in the Activity module as shown below
Before
@Module
public abstract class ActivityBuilder {
@ContributesAndroidInjector(modules =
{ItemDetailActivityModule.class})
abstract ItemDetailActivity contributeItemDetailActivity();
}
After - Now add the ViewModel that corespond to the above activity in my case it is ItemDetailViewModel class
@Module
public abstract class ActivityBuilder {
@ContributesAndroidInjector(modules =
{ItemDetailActivityModule.class,ItemDetailProvider.class})//<--- provider added in this line
abstract ItemDetailActivity contributeItemDetailActivity();
}
Upvotes: 1