19

When using Dagger, I found that I'm getting multiple instances of a singleton when I inject it wherever I need it. I've annotated the class and the provides method with @Singleton. Can anyone think of why this is happening?

Edit:

If it helps, I have followed the same structure for my app as the sample application in Dagger's GitHub (https://github.com/square/dagger/tree/master/examples/android-activity-graphs). I'm trying to get the Singleton in the base activity and a couple of third party classes provided using @Provides at the custom Application class. Is it because I'm plus-ing modules at each activity to the original object graph?

(PS : I'm new to Dagger and DI in general, so I'll be grateful if you could provide an explanation so that I may learn. Thanks.)

Christian Gruber
  • 4,691
  • 1
  • 28
  • 28
Raghuveer
  • 1,737
  • 20
  • 27

1 Answers1

39

@Singleton, in Dagger 1.x, acts differently than you might think. The JSR-330 spec definition in the @Singleton javadoc is "one per graph" and that is how Dagger interprets it.

So if you have something that is marked as @Singleton, and it is materialized in your application graph (as opposed to a shorter-lifetime graph), then you get one instance per application.

If you have an item annotated @Singleton that's in the modules you use to configure your activity graph (i.e., that is obtained from the part of a graph specified by a module used in the plus() operation) then you will get one-per-activity-graph.

If you need something to be once-per-application, you need to make sure it gets created as a part of the application graph. You can do this in one of two ways. Either explicitly provide it with an @Provides method from your application module(s), or you can list it as a one of the classes in @Module(injects=...) in an application module.

(If you do not mark it with @Singleton than you will get one per injection site.)

So remember, the graph created by plus() is seen as a separate graph that points to the graph from which it was spawned, and wraps it, can access instances within it, but is not the same graph.

Note - Dagger 2.x improves this, and supports custom scoping annotations, though the mechanism is similar, with one graph (component) per scope annotation, with a parent/child relationship between graphs of wider/narrower lifetimes

Christian Gruber
  • 4,691
  • 1
  • 28
  • 28
  • Thanks for clearing that up. When you say spec, are you referring to JSR330? – Raghuveer Jul 04 '13 at 09:25
  • @ChristianGruber How does this apply to Singleton injected Constructors used in various sub-graphs of a parent graph? Does that mean one-per-graph the class is used in, except when it already exists in a parent graph? – vinc3m1 Mar 10 '14 at 22:52
  • 1
    Sort of. If everything is bound "just in time" then yes, that's exactly it. If you use a thing marked Singleton, it'll be created in the graph that first requests it. So if you want it created in a parent graph (or the root graph) you need to give Dagger a means to know about it in that longer-lived graph, either by providing it in a `@Provides` method, or by declaring it in the `injects=` property of a module annotation in the longer-lived graph. – Christian Gruber Mar 10 '14 at 22:59
  • 1
    cool! I thought `@Provides` was clumsy and not DRY, didn't know `injects=` worked too, will use that. – vinc3m1 Mar 14 '14 at 18:49
  • @vinc3m1 an even more DRY approach would be to put the `@Singleton` on the class definition of your item instead of in the `@Prodices` block or the `@Modules{inject=...}` specification as the class level `@Singleton` annotation qualifies it as a singleton to the graph. – Nthalk Apr 01 '15 at 23:37
  • @Nthalk my question assumed `@Singleton` annotation already. The problem is when there are subgraphs and it's unclear which graph scope the singleton is tied to. – vinc3m1 Apr 03 '15 at 00:07