从匕首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.
答案 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
一次,并在Activities
或Fragments
等其他地方静态访问,现在如果你有这种情况,这很快就会失控超过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输出为
注意:
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>
* @Singleton
* class Log {
* void log(String message) { ... }
* }</pre>
你明白了吗?无论你使用什么注释,或者你创建一个自定义注释,它们都会从@Scope继承,它将确保为单例。