Dagger 2 - какова цель класса аннотации @Singleton

Из документации кинжала 2 я заметил, что у вас может быть @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.

person j2emanue    schedule 28.06.2015    source источник
comment
Как именно вы пришли к выводу, что одноэлементный объект не создается? Фактически он производит синглтон. См. Также мой ответ здесь.   -  person nhaarman    schedule 01.07.2015
comment
да, я не понимал, что вам нужно пометить конструктор аннотацией Inject, чтобы он работал. Благодарю.   -  person j2emanue    schedule 04.07.2015
comment
Я не нахожу аннотации @Injected. Действительно ли мы используем @Inject как в конструкторе, так и в классе, в котором вы хотите его создать?   -  person Ethan_AI    schedule 22.02.2016
comment
извините, я обновил блок кода. @Inject в конструкторе позволяет не объявлять зависимость в модуле. это ярлык для объявления в модуле. Я пишу об этом в блоге здесь: j2emanue.blogspot.ca/2015/12/   -  person j2emanue    schedule 22.02.2016
comment
Напоминаем: @Singleton необходимо применять как в классе Injectable, так и в интерфейсе Component. Этот момент отсутствует в официальном документе Dagger официальном документе.   -  person Freddie    schedule 16.11.2018


Ответы (5)


@Singleton (и любая другая аннотация области) делает ваш класс единственным экземпляром в вашем графике зависимостей (это означает, что этот экземпляр будет «одиночным», пока существует объект Component).

Короче говоря, каждый раз, когда вы вводите @Singleton аннотированный класс (с аннотацией @Inject), он будет одним и тем же экземпляром, пока вы вводите его из одного и того же компонента.

Для получения дополнительной информации я ссылаюсь на свое сообщение в блоге о том, как аннотации @Singleton и других областей видимости работают в Dagger 2: http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/

person froger_mcs    schedule 02.07.2015
comment
Привет, хорошая статья об определении объема работ. Но мой вопрос не в том, чтобы пометить аннотацию @Singleton для поставщика в модуле. Я говорю о том, чтобы пометить его на самом экземпляре класса. Если бы вы могли сказать мне, все ли оно используется для документации, как написано в dagger doc, было бы здорово. Я сам пробовал, и он сам по себе не создал ни одного синглтона. Требовалось, чтобы провайдер был помечен как синглтон. - person j2emanue; 03.07.2015
comment
Итак - пока вы используете @Singleton для аннотирования самого класса, вы также должны использовать аннотацию @Inject для конструктора. Это сделает ваш класс частью графика зависимостей. И каждый раз, когда вы где-то вводите этот конкретный класс, это будет один и тот же экземпляр. Для лучшего понимания вы можете попробовать мой проект, который показывает, как работает Dagger 2. Пример класса, который показывает вашу проблему, находится здесь: github.com/frogermcs/GithubClient/blob/ - person froger_mcs; 03.07.2015
comment
Для меня любой компонент, который я использую в методе поставщика, будет одноэлементным. Имя singleton в этом случае на самом деле просто означает оставаться в живых, пока жив компонент, не создавайте другой экземпляр. - person j2emanue; 13.01.2016
comment
Но я до сих пор не понимаю, почему @Singleton используется как в классе, так и в методе обеспечения. Они оба используются? Они оба требуются? Кажется, что отсутствие аннотации Singleton в классе по-прежнему приводит к успешной сборке. - person WindRider; 12.07.2016
comment
@WindRider, насколько я понимаю, вы говорите об аннотациях модулей. Для классов модуля нам вообще не нужно помещать аннотацию класса, поскольку это не имеет никакого смысла. Синглтон в качестве аннотации класса следует использовать только для компонентов, определяющих область действия компонента, или для классов, которые представляют себя без модулей. Синглтон как аннотация метода должен быть помещен только в методы, предоставляемые модулем, для определения предоставленного объекта как синглтона. - person vbevans94; 03.02.2017
comment
@ vbevans94 Знаете ли вы, требуются ли аннотации метода Singleton в методах обеспечения, если у Компонента уже есть аннотированная область действия Singleton? - person fhsilva; 05.06.2017
comment
@fhsilva, да, это так. - person vbevans94; 06.06.2017
comment
@ vbevans94 Спасибо! В таком случае знаете ли вы, что значит иметь методы поставщика Singleton Component и не-singleton? - person fhsilva; 06.06.2017
comment
Но когда мы узнаем, что используем аннотацию Singleton или нет? - person ASN; 10.06.2018

@Singleton на самом деле не создает синглтон, это просто Scope, рекомендуется не использовать @Singleton, поскольку это вводит в заблуждение, создается впечатление, что мы фактически получаем синглтон, но это не так.

Допустим, вы аннотируете зависимость своей базы данных с помощью @Singleton и связываете с помощью Component, теперь предположим, что вы инициализируете этот Component в Activities A и B, у вас будут разные экземпляры вашей базы данных в ваших двух Activities, чего большинство людей не хочет .

Как с этим справиться?

Инициализируйте свой Component один раз в классе Application и обращайтесь к нему статически в других местах, таких как Activities или Fragments, теперь это может скоро выйти из-под контроля, если у вас больше 20 Component's, поскольку вы не можете инициализировать все из них в своем классе Application, это приведет к также замедлите время запуска вашего приложения.

На мой взгляд, лучшее решение - создать реальный Singleton, либо с двойной проверкой, либо с другими вариантами, и использовать его статически как getInstance() и использовать его под @Provides в вашем модуле.

Я знаю, что это тоже разбивает мне сердце, но, пожалуйста, поймите, что @Singleton на самом деле не Singleton, это Scope.

person Arif Nadeem    schedule 29.05.2017
comment
я написал это некоторое время назад. да аннотация синглтона - это область видимости. он применяет синглтон только в течение срока службы компонента. Это похоже на наличие локального синглтона, который сохраняется только на время жизни компонента. - person j2emanue; 29.05.2017
comment
Я думаю, что это довольно нормальный шаблон для создания компонента в методе создания приложения, поэтому есть один компонент, а синглтоны - это синглтоны. - person Greg Ennis; 22.06.2017
comment
Да, вы можете, но если ваше приложение довольно большое и у вас более 20 компонентов, инициализация всех из них в классе Application замедлит время запуска вашего приложения, а также класс Application будет раздутым. - person Arif Nadeem; 22.06.2017
comment
Вы бы семантически рекомендовали использовать @AppScoped вместо @Singleton? Я также использую @ActivityScoped и @FragmentScoped в своем проекте - person Eido95; 28.10.2018
comment
@ Eido95 Я определенно хотел бы, Синглтон невероятно вводит в заблуждение из-за своей семантики, это серьезная проблема для людей, которые только изучают Dagger, до такой степени, что я не уверен, почему он используется во многих руководствах вместо создания пользовательской аннотации . - person Eduardo Naveda; 19.01.2019
comment
пожалуйста, поймите, что @Singleton на самом деле не Singleton, это Scope точно так же, как Dagger не является библиотекой DI, это процессор аннотаций, который многие люди не получают - person Marian Paździoch; 16.04.2019

Что такое синглтон?

Шаблон Singleton в Android

Единственный экземпляр класса, обеспечивающий глобальную точку доступа к самому себе в течение всего времени существования приложения.

Аннотация @Singleton в Dagger

Один экземпляр класса, который уникален для определенного компонента, его доступ ограничен областью действия компонента.

Назначение синглтона

Чтобы предоставить единственный экземпляр класса в графе зависимостей (компонент). компонент обычно инициализируется на уровне приложения, поскольку он выполняет только компоненты в течение всего времени существования приложения и доступен для всех действий и фрагментов.

Возьмем пример:

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
}

Рекомендуемая практика

Всегда идите на ленивую инициализацию вашего компонента.
Сценарий: скажем, вы - команда, решившая добавить экран подключения / обучения или включить какой-либо другой дизайн, который не требует компонента во время начальных экранов, это поможет минимизировать запуск задерживать. Всегда помните, инициализация компонента стоит дорого.

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


Если ваш класс дорого строить, используйте ленивую инициализацию кинжала, пожалуйста, не путайте ее с ленивой kotlin. Вы должны импортировать

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

вы получите вывод журнала как

application_singleton

Примечание.

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

person Extremis II    schedule 19.07.2019

Ну, вы можете вручную создать аннотацию, которая поможет создать объект singleton.

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

Когда @MyApplicationScope аннотация добавляется с аннотацией @Provides, это заставляет кинжал создать объект только один раз и использовать тот же объект в будущем. Не забудьте добавить эту аннотацию в интерфейс компонента, иначе во время компиляции вы получите ошибку, связанную с областью видимости.

Если вы используете аннотацию @Singleton, вы можете создавать новые объекты каждый раз, когда будете создавать свой компонент с помощью .build().

person Levon Petrosyan    schedule 07.05.2018

@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, это будет гарантировать как синглтон.

person raditya gumay    schedule 21.09.2017
comment
Если вы цитируете какой-либо источник, всегда включайте ссылку на источник в свой текст. - person TT.; 21.09.2017
comment
это в документации @Scope - person raditya gumay; 21.09.2017
comment
Конечно, но ссылка на источник - обычное дело. - person TT.; 21.09.2017