Dagger 2 - @Singleton注释类的目的是什么

时间:2015-06-28 12:56:06

标签: dependency-injection dagger dagger-2

从匕首2 Documentation我注意到你可以有一个@Singleton注释类。将类标记为@Singleton的目的是什么,因为我试图在我的代码中执行此操作,但不生成单个对象。我不清楚用这个注释标记我的类的用途。

请从文档中关注以下声明:

  

注射类上的@Singleton注释也可用作   文档。它提醒潜在的维护者这个类可能是   由多个线程共享。*

@Singleton
class CoffeeMaker {
  ...
}

更新:在查看froger_mcs答案后,我看到在Dagger 2中你可以通过模块或构造函数注入提供注射。因此,可以注入以下类,但不在模块中:

@Singleton
public class MyClass {

    @Inject
    public MyClass() {

    }
}

在这个版本中,构造函数是为我们注入的,在Android活动中你只需执行以下操作即可获得:

@Inject
MyClass myClass;
//then in onCreate actually inject(this) from your graph of course.

5 个答案:

答案 0 :(得分:41)

@Singleton(以及任何其他范围注释)使您的类成为依赖关系图中的单个实例(这意味着该实例将是" singleton"只要Component对象存在)。

简而言之 - 每次您注入@Singleton带注释的类(带@Inject注释)时,只要您从同一个组件中注入它,它就会是同一个实例。

有关更多信息,请参阅我的博客文章,了解@Singleton和其他范围注释在Dagger 2中的工作原理:http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/

答案 1 :(得分:23)

@Singleton并没有真正创建一个单身人士,它只是一个Scope,建议不要使用@Singleton,因为它有误导性,它给人的印象是我们实际上得到了单身人士,但我们不是。

假设您使用@Singleton注释数据库相关性并与Component相关联,现在假设您在Component Activities中初始化此A并且B,您的两个Activities中将有不同的数据库实例,这是大多数人不想要的。

你是如何克服这个的?

Component课程中初始化Application一次,并在ActivitiesFragments等其他地方静态访问,现在如果你有这种情况,这很快就会失控超过20 Component's,因为您无法在Application课程中初始化所有这些内容,这样做也会减慢您的应用发布时间。

根据我的最佳解决方案是创建一个真实的Singleton,要么经过双重检查,要么使用其他变体,并将其静态地用作getInstance(),并在模块中的@Provides下使用此解决方案。

我知道这也让我心碎,但请理解@Singleton不是Singleton,而是Scope

答案 2 :(得分:2)

什么是单例?

Android中的单一模式

  

类的单个实例,在整个应用程序的生命周期内,提供对自身的全局访问点。

@Dagger中的单个注释

  

一个类的单个实例,对某个特定组件是唯一的,其访问仅限于该组件的范围。

单例目的

在依赖关系图(组件)中提供类的单个实例。组件通常在应用程序级别进行初始化,因为它在整个应用程序生命周期中仅执行一个组件,并且所有活动和片段都可以对其进行访问。

让我们举个例子:

CoffeeComponent.kt

 Optional(5) 
 Optional(15) 
 Optional(2)

CoffeeMaker.kt

@Singleton
@Component
interface CoffeeComponent {

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

CoffeeAplication.kt

@Singleton
class CoffeeMaker @Inject constructor()

推荐做法

  

总是进行组件的惰性初始化。
方案:例如,您的团队决定添加一个入门/教程屏幕或合并一些其他设计,这些设计在初始屏幕中不需要该组件,它将帮助最小化启动延迟。永远记住,组件初始化非常昂贵。

ActivityA.kt

class CoffeeApplication : Application() {

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

  fun getAppComponent(): CoffeeComponent = component
}


    如果您的类构造昂贵,请使用匕首的Lazy初始化,请不要将其与Kotlin的Lazy混淆。您必须导入

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()}") } }

import dagger.Lazy

ActivityB.kt

@Inject
lateinit var coffeeMaker1:Lazy<CoffeeMaker>

您将获得Log输出为

application_singleton

注意

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()}") } }

答案 3 :(得分:1)

您可以手动创建注释,这有助于创建单件对象。

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

@MyApplicationScope注释添加@Provides注释时,它使匕首只创建一个对象一次,并在将来使用相同的对象。 请记住将此注释添加到组件接口,否则您将在编译期间获得与范围相关的错误。

如果您使用@Singleton注释,则每次使用.build()创建组件时,最终都可能会创建新对象。

答案 4 :(得分:-1)

@Singleton继承@Scope,因此在文档中说

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>

你明白了吗?无论你使用什么注释,或者你创建一个自定义注释,它们都会从@Scope继承,它将确保为单例。