62

From the dagger 2 Documentation I noticed that you can have a @Singleton annotated class. What is the purpose of marking a class as @Singleton as I have tried to do this in my code but a singleton object is NOT produced. I'm not clear on what use marking my class with this annotation serves.

From the documentation please focus on the following statement:

The @Singleton annotation on an injectable class also serves as documentation. It reminds potential maintainers that this class may be shared by multiple threads.*

@Singleton
class CoffeeMaker {
    // ...
}

UPDATE: After reviewing froger_mcs answer I see that in Dagger 2 you can provide injections either by a module OR by a constructor injection. So the following class, although not in a module, can be injected:

@Singleton
public class MyClass {
    @Inject
    public MyClass() {

    }
}

In this version the constructor is injected for us and in an Android activity you would just do the following and it will get provided:

@Inject
MyClass myClass;
//then in onCreate actually inject(this) from your graph of course.
stkent
  • 19,772
  • 14
  • 85
  • 111
j2emanue
  • 60,549
  • 65
  • 286
  • 456
  • How exactly did you conclude no singleton object is produced? It in fact does produce a singleton. See also my answer [here](http://stackoverflow.com/a/30360675/675383). – nhaarman Jun 30 '15 at 21:28
  • yah i didn't realize you had to mark the constructor with Inject annotation for it to work. thanks. – j2emanue Jul 04 '15 at 15:35
  • I'm not finding the `@Injected` annotation. Do we actually use `@Inject` in both the constructor and the class you want to instantiate it in? – Ethan_AI Feb 22 '16 at 18:10
  • sorry there was a type i updated the code block. @Inject on the constructor makes it so you dont have to declare dependency in module. its a shortcut to declaring in module. I blog about it here: http://j2emanue.blogspot.ca/2015/12/lesson-2-dagger2-provider-object-with.html?view=magazine – j2emanue Feb 22 '16 at 18:55
  • Just a reminder: @Singleton must be applied both in the Injectable class and the Component interface. This point is missed in [Dagger's official document](https://google.github.io/dagger/users-guide) official document. – Freddie Nov 16 '18 at 03:46

5 Answers5

72

@Singleton (and any other scope annotation) makes your class a single instance in your dependencies graph (it means that this instance will be "singleton" as long as Component object exists).

In short - everytime you're injecting @Singleton annotated class (with @Inject annotation) it will be the same instance as long as you inject it from the same Component.

For more I'm referring my blog post about how @Singleton and other scopes annotations works in Dagger 2: http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/

froger_mcs
  • 13,972
  • 5
  • 23
  • 34
  • 2
    Hey nice article on scoping. But my question is not tagging @Singleton annotation on a provider in a module. I am talking about tagging it on a class instance itself. If you could tell me if all its used for is for documentation as the dagger doc says it would be great. I tried it myself and it did not create a singleton on its own. It needed a provider to be tagged as singleton. – j2emanue Jul 03 '15 at 13:26
  • 4
    So - while you're using `@Singleton` to annotate class itself you should also use `@Inject` annotation for constructor. It'll make your class part of dependencies graph. And everytime you inject this particular class somewhere it will be the same instance. For better understand you can try my project which shows how Dagger 2 works. Example class which shows your problem is here: https://github.com/frogermcs/GithubClient/blob/1bf53a2a36c8a85435e877847b987395e482ab4a/app/src/main/java/frogermcs/io/githubclient/utils/AnalyticsManager.java – froger_mcs Jul 03 '15 at 13:44
  • 1
    To me any component scope that is i use on a provider method will be singleton. The name singleton in this case really just means stay alive as long as the component is alive, dont create another instance. – j2emanue Jan 13 '16 at 18:09
  • 2
    But I still don't understand why `@Singleton` is used both on the class and the "provides" method. Are they both used? Are they both required? It seems that omitting the "Singleton" annotation on the class still results in successful build. – WindRider Jul 12 '16 at 08:09
  • @WindRider as far as I understand you are talking about module annotations. For module classes we don't need to put class annotation at all as it doesn't make any sense. Singleton as a class annotation should only be put for Components to define the scope of component or to classes that exposes themselves without modules. Singleton as a method annotation should be put only on Module's "provide"s methods to define provided object as singleton. – vbevans94 Feb 03 '17 at 12:38
  • @vbevans94 Do you know if the Singleton method annotations on "provide"s methods are required when the Component already has a Singleton annotated scope? – fhsilva Jun 05 '17 at 19:31
  • @fhsilva yes it is. – vbevans94 Jun 06 '17 at 10:01
  • 1
    @vbevans94 Thanks! In that case, do you know what means to have a Singleton Component and non-singleton provider methods? – fhsilva Jun 06 '17 at 10:24
  • But when do we know that we have use `Singleton` annotation or not? – ASN Jun 10 '18 at 17:06
46

@Singleton does not really create a Singleton, it is just a Scope, it is advised to not use @Singleton as it is misleading, it gives the impression that we are infact getting a Singleton, but we are not.

Let's say you annotate your database dependency with @Singleton and link with a Component, now let's say that you initialise this Component in Activities A and B, you will have different instances of your database in your two Activities which is something most people don't want.

How do you overcome this?

Initialise your Component once in your Application class and access it statically in other places like Activities or Fragments, now this could soon get out of hand if you have more than 20 Component's as you cannot initialise all of them in your Application class, doing so will also slow down your app launch time.

The best solution according to me is to create a real Singleton, either double checked or of other variants and use this statically as getInstance() and use this under @Provides in your Module.

I know it breaks my heart too, but please understand that @Singleton is not really a Singleton, it's a Scope.

Arif Nadeem
  • 8,524
  • 7
  • 47
  • 78
  • i wrote this a while back. yes singleton annotation is a scope. its enforces singleton within the lifetime of the component only. Its like having a local singleton thats only kept alive for the lifetime of the component. – j2emanue May 29 '17 at 20:20
  • 5
    I think its pretty normal pattern to create the component in the Application create method, therefore there's one component and singletons are singletons. – Greg Ennis Jun 21 '17 at 21:51
  • Yes you can, but if your app is fairly huge and if you have more than 20 components, initialising all of them in Application class would slow down your app start time, also the Application class will be bloated. – Arif Nadeem Jun 22 '17 at 06:23
  • 1
    Would you semantically recommend to use `@AppScoped`, instead of `@Singleton`? I'm also use `@ActivityScoped` and `@FragmentScoped` in my project – Eido95 Oct 28 '18 at 08:59
  • 2
    @Eido95 I definitely would, Singleton is incredibly misleading due to its semantics, it's a major pain point for people just learning Dagger as well, to the point I'm not sure why it is used in so many tutorials instead of creating a custom annotation. – Eduardo Naveda Jan 18 '19 at 22:49
  • "please understand that @Singleton is not really a Singleton, it's a Scope" exactly the same as Dagger is not DI library, it's annotation processor which many people don't get – Marian Paździoch Apr 16 '19 at 12:34
  • 1
    This post is a bit misleading. If you use the singleton component, and return a singleton dependency, then the dependency is a singleton, and Dagger already uses double locking internally. No need to go about creating your own singleton. And you can absolutely inject repositories. – the_prole Aug 16 '22 at 20:04
  • I profoundly disagree with this answer. If you're doing DI correctly then all the consumers of your singleton should be living inside that component scope. It _is_ a singleton, in the context of its component (which is all that matters to dagger) – forresthopkinsa Dec 20 '22 at 18:49
11

What is singleton?

Singleton Pattern in android

A single instance of a class providing a global point of access to itself during the entire application's lifetime.

@Singleton annotation in Dagger

A single instance of a class which is unique to a specific component, its access is limited to the scope of the component.

Purpose of singleton

To provide a single instance of a class within the dependency graph(component). a component is usually initialized in the application level as it executes only ones for the entire applications lifetime and is accessible by all activities and fragment.

Let's take an example:

CoffeeComponent.kt

@Singleton
@Component
interface CoffeeComponent {

  fun getCoffeeMaker():CoffeeMaker
  fun inject(activityA: ActivityA)
  fun inject(activityB: ActivityB)
}

CoffeeMaker.kt

@Singleton
class CoffeeMaker @Inject constructor()

CoffeeAplication.kt

class CoffeeApplication : Application() {

  private val component by lazy {
    DaggerCoffeeComponent.builder().build()
  }

  fun getAppComponent(): CoffeeComponent = component
}

Recommended Practise

Always go for lazy initialization of your component.
Scenario: say, you are team decided to add an onboarding/tutorial screen or incorporate some other design which doesn't require the component during the initial screens, it will help minimize the startup delay. Always remember, component initialization is expensive.

ActivityA.kt

import dagger.Lazy

class ActivityA: AppCompatActivity() {

  @Inject
  lateinit var coffeeMaker1:Lazy<CoffeeMaker>
  @Inject
  lateinit var coffeeMaker2:Lazy<CoffeeMaker>
  private val component by lazy {
    (application as CoffeeApplication).getAppComponent()
}
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    btn_activityB.setOnClickListener { startActivity(Intent(this, NewActivity::class.java)) }

    component.inject(this)

    println("Activity A CoffeeMaker 1 - ${coffeeMaker1.get()}")
    println("Activity A CoffeeMaker 2 - ${coffeeMaker2.get()}")
  }
}


If your class is expensive to construct, use the dagger's Lazy initialization, please don't confuse it with kotlin's Lazy. You have to import

import dagger.Lazy

@Inject
lateinit var coffeeMaker1:Lazy<CoffeeMaker>

ActivityB.kt

class ActivityB: AppCompatActivity() {

@Inject
lateinit var coffeeMaker1:Lazy<CoffeeMaker>
@Inject
lateinit var coffeeMaker2:Lazy<CoffeeMaker>
private val component by lazy { 
(application as CoffeeApplication).getAppComponent() }

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_new)
    component.inject(this)

    println("Activity B CoffeeMaker 1 - ${coffeeMaker1.get()}")
    println("Activity B CoffeeMaker 2 - ${coffeeMaker2.get()}")
}
}

you will get the Log output as

application_singleton

Note:

If you want to share a singleton instance between activities, lazily initialize them in the application level, if you initialize them in an activity you will end up with different instance as the components are different

Extremis II
  • 5,185
  • 2
  • 19
  • 29
1

Well you can manually create an annotation,which will help to create a singleton object.

@Scope
@Retention(RetentionPolicy.CLASS)
public @interface MyApplicationScope {
}

When @MyApplicationScope annotation is added with @Provides annotation than it makes dagger to create an object only once and use same object in future. Do remember to add this annotation to the component interface also otherwise you will get the scope related error during compilation.

If you are using @Singleton annotation then you may end up creating the new objects every time when you will create your component with .build().

Levon Petrosyan
  • 8,815
  • 8
  • 54
  • 65
-1

@Singleton is inherit @Scope, so in documentation says

Identifies scope annotations. A scope annotation applies to a class * containing an injectable constructor and governs how the injector reuses * instances of the type. By default, if no scope annotation is present, the * injector creates an instance (by injecting the type's constructor), uses * the instance for one injection, and then forgets it. If a scope annotation * is present, the injector may retain the instance for possible reuse in a * later injection. If multiple threads can access a scoped instance, its * implementation should be thread safe. The implementation of the scope * itself is left up to the injector. <p>In the following example, the scope annotation {@code @Singleton} ensures * that we only have one Log instance: * * <pre> * &#064;Singleton * class Log { * void log(String message) { ... } * }</pre>

You get the point right? whatever annotation you use or you create a custom one, and they inherit from @Scope it will ensure as singleton.

raditya gumay
  • 2,951
  • 3
  • 17
  • 24