My Dagger2 Component class contains 3 modules which I'm trying to use to inject field dependencies into an Android Activity class. The generated Component file has comments saying all the modules are unused, linking this page for more info.
My Activity class is calling the Component's inject(Activity) method and has fields annotated for injection that are provided by the modules, so I am not sure why the generated Component file does not have any Providers to do this injection.
My code is below, thanks for the help!
Generated Component Class:
public final class DaggerMainComponent implements MainComponent {
private DaggerMainComponent(Builder builder) {
assert builder != null;
}
public static Builder builder() {
return new Builder();
}
public static MainComponent create() {
return builder().build();
}
@Override
public void inject(Activity activity) {
MembersInjectors.<Activity>noOp().injectMembers(activity);
}
public static final class Builder {
private Builder() {}
public MainComponent build() {
return new DaggerMainComponent(this);
}
/**
* @deprecated This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
*/
@Deprecated
public Builder daoModule(DaoModule daoModule) {
Preconditions.checkNotNull(daoModule);
return this;
}
/**
* @deprecated This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
*/
@Deprecated
public Builder repositoryModule(RepositoryModule repositoryModule) {
Preconditions.checkNotNull(repositoryModule);
return this;
}
/**
* @deprecated This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
*/
@Deprecated
public Builder portableModule(PortableModule portableModule) {
Preconditions.checkNotNull(portableModule);
return this;
}
}
}
Non-Generated Component Class:
@Component(modules={DaoModule.class,RepositoryModule.class,PortableModule.class})
public interface MainComponent {
void inject(Activity activity);
}
Module Classes: Is there any issue with having one module provide an object with a dependency on another object provided by another module belonging to the same Component?
@Module
public class DaoModule {
private DatabaseHelper databaseHelper;
public DaoModule(DatabaseHelper databaseHelper){
this.databaseHelper = databaseHelper;
}
@Provides
public Dao<Player,Integer> providePlayerDao(){
return databaseHelper.getPlayerDao();
}
@Provides
public Dao<GamePlayed,Integer> provideGamePlayedDao() {
try {
return databaseHelper.getDao(GamePlayed.class);
} catch (SQLException e) {
return null;
}
}
@Provides
public Dao<GamePlayer,Integer> provideGamePlayerDao() {
try {
return databaseHelper.getDao(GamePlayer.class);
} catch (SQLException e) {
return null;
}
}
}
...
@Module
public class RepositoryModule {
@Provides
public IGameResultRepository provideGameResultRepository(
Dao<Player,Integer> playerDao,
Dao<GamePlayed,Integer> gameDao,
Dao<GamePlayer, Integer> gamePlayerDao)
{
return new OrmliteGameResultRepository(playerDao,gameDao,gamePlayerDao);
}
}
@Module
public class PortableModule {
@Provides
public GameResultListener provideGameResultListener(IGameResultRepository gameResultRepository){
return new GameResultListener(gameResultRepository);
}
}
Application Class:
public class AppStart extends Application {
private MainComponent mainComponent;
@Override
public void onCreate() {
super.onCreate();
DatabaseHelper databaseHelper = new DatabaseHelper(getApplicationContext());
mainComponent = DaggerMainComponent.builder()
.daoModule(new DaoModule(databaseHelper))
.build();
}
public MainComponent getMainComponent(){
return mainComponent;
}
}
Activity Class:
public class MyActivity extends Activity {
@Inject GameResultListener gameResultListener;
@Inject Dao<Player,Integer> dao;
@Inject IGameResultRepository repository;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
((AppStart)this.getApplication()).getMainComponent().inject(this);
Modules are a way of telling Dagger how to provide dependencies from the dependency graph. These are typically high level dependencies that you aren't already contributing to the dependency graph through the @Inject constructor annotation we discussed in our previous article.
It's officially deprecated and you can pretty much ignore it. Google's framework, which became dominant in Android ecosystem, was originally called Dagger 2. Sometimes we still refer to it as such, but, in most cases, we simply call it Dagger today.
For a fast read, a Component in Dagger is an unit which is essentially used to resolve dependencies. A Module is a sub-unit, providing dependencies, one or several of which can be used by a Component. A SubComponent is a type of Component which derives from a Component, inheriting the dependencies it already provides.
With the @Inject annotation on the constructor, we instruct Dagger that an object of this class can be injected into other objects. Dagger automatically calls this constructor, if an instance of this class is requested.
Question 1: Why are my modules being marked as "unused"?
You have not supplied the correct injection site! As it stands, your component interface is one with the sole injection site of android.app.Activity
. Since android.app.Activity
has no @Inject
annotations on its fields then you get a no-op members injector. Similarly, your modules are marked as unused because none of them are actually being used as sources of dependencies for android.app.Activity
. To fix this, in your component change:
void inject(Activity activity);
to:
void inject(MyActivity myActivity);
Question 2:
Is there any issue with having one module provide an object with a dependency on another object provided by another module belonging to the same Component?
No, this is perfectly fine. To illustrate, let's take a simple object graph:
public class Foo {
public Foo(FooDependency fooDependency) {}
}
public class FooDependency {
FooDependency(String name) {}
}
We want to inject it inside the following class using Dagger:
public class FooConsumer {
@Inject Foo foo;
private FooConsumer() {}
}
We would like to reuse a module binding FooDependency
so we'll write two separate modules:
@Module
public class FooModule {
@Provides
Foo foo(FooDependency fooDependency) {
return new Foo(fooDependency);
}
}
@Module
public class FooDependencyModule {
@Provides
FooDependency fooDependency() {
return new FooDependency("name");
}
}
And the following component interface:
@Component(modules = {FooModule.class, FooDependencyModule.class})
public interface FooComponent {
void inject(FooConsumer fooConsumer);
}
The generated component DaggerFooComponent
contains the following code that will correctly use the FooDependency
from the separate module FooDependencyModule
to inject Foo
:
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.fooDependencyProvider =
FooDependencyModule_FooDependencyFactory.create(builder.fooDependencyModule);
this.fooProvider = FooModule_FooFactory.create(builder.fooModule, fooDependencyProvider);
this.fooConsumerMembersInjector = FooConsumer_MembersInjector.create(fooProvider);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With