I just tested out Dagger 2 and I am having some strange behaviour regarding the singleton annotation. I created some test code to show my problem.
My Module:
@Module
public class App {
@Provides
@Singleton
ThingA provideThingA(){
return new ConcreteThingA();
}
}
Interface of the thing I want in singleton:
public interface ThingA {
void showMyId();
}
Implementation:
public class ConcreteThingA implements ThingA {
@Override
public void showMyId() {
System.out.println(this);
}
}
Code that executes Dagger:
public void doStuff() {
ThingA thingA=DaggerThingAComponent.create().provideThingA();
ThingA thingB=DaggerThingAComponent.create().provideThingA();
System.out.println("Hello");
}
And here is a screenshot showing that I do not get the same instance when I ask for it twice. Have I missed something fundamental? ThingA is just a silly name and in my actual application I would like to have this singleton behaviour on my services.
The trick is that Dagger enforces scope/lifecycle through components, and you've created two separate components here:
Each time you create the new top-level @Singleton-annotated Component, Dagger creates a brand new object graph with a brand new container for each @Singleton object. You should have this instead:
Of course, anything further accessed through the dependency graph all comes from the same component, so this will preserve the singleton behavior you're looking for.
In most cases, you should not need to pass around the Component: The Component should be used for top-level components, and anything accessible through the injector should @Inject its dependencies (which means it shouldn't need a reference to the component itself). This might appear problematic during the migration to DI or Dagger, but creating multiple @Singleton components is not the way around it. Instead, try one of the following:
Provider<T>
instead ofT
whether or not you've created a@Provides
method. For that matter, you can inject aLazy<T>
if you only need zero or one copies of a particular dependency, particularly if the creation of that object is particularly heavy.@Inject Provider<T> tProvider
instead of@Inject YourComponent
just to callYourComponent.getT
.See also: Bindings in the graph from the Dagger 2 Users Guide