Как долго живет зависимость помеченная аннотацией Singleton в Dagger
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Время жизни Singleton в Dagger
В Dagger 2 аннотация @Singleton определяет время жизни зависимости в рамках одного компонента (Component). Это ключевой момент: "долгота жизни" привязана не к приложению в целом, а к конкретному экземпляру компонента, который её предоставляет.
Основной принцип
- @Singleton — это scope (область видимости/времени жизни). Она не создаёт синглтон в классическом понимании (как статическое поле в классе). Вместо этого Dagger гарантирует, что в рамках одного экземпляра компонента будет создан и переиспользован ровно один экземпляр помеченного класса.
- Зависимость живет столько же, сколько живет компонент. Когда компонент уничтожается (становится доступным для сборщика мусора), все его "синглтон"-зависимости также могут быть собраны. В Android это напрямую связано с жизненным циклом Activity, Fragment или Application.
Практические примеры в Android
1. Singleton в рамках ApplicationComponent
Это самый распространённый и "долгоживущий" случай.
// Модуль
@Module
class AppModule {
@Singleton
@Provides
fun provideHeavyDependency(): HeavyDependency {
return HeavyDependency()
}
}
// Компонент, привязанный к жизненному циклу Application
@Singleton
@Component(modules = [AppModule::class])
interface ApplicationComponent {
fun inject(activity: MainActivity)
fun getHeavyDependency(): HeavyDependency
}
// В кастомном классе Application
class MyApp : Application() {
lateinit var appComponent: ApplicationComponent
override fun onCreate() {
super.onCreate()
appComponent = DaggerApplicationComponent.create()
}
}
Время жизни: Зависимость HeavyDependency создается при первой необходимости после построения ApplicationComponent и живет до тех пор, пока живет объект appComponent, то есть, практически, всё время жизни приложения (пока процесс не будет убит). Это максимально возможное время жизни для @Singleton в Android.
2. Singleton в рамках ActivityComponent (или другого подкомпонента)
Здесь поведение меняется кардинально.
// Допустим, есть Scope для Activity
@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class ActivityScope
// Модуль Activity
@Module
class ActivityModule {
@ActivityScope // Или @Singleton, если компонент Activity изолирован
@Provides
fun provideActivityScopedDependency(): ActivityScopedDep {
return ActivityScopedDep()
}
}
// Подкомпонент для Activity
@ActivityScope
@Subcomponent(modules = [ActivityModule::class])
interface ActivityComponent {
fun inject(fragment: MyFragment)
}
Время жизни: Если @Singleton (или кастомный @ActivityScope) используется в модуле ActivityModule, а компонент ActivityComponent создается при старте Activity и не сохраняется между пересозданиями, то зависимость будет жить только пока жива эта конкретная Activity. При повороте экрана и пересоздании Activity будет создан новый компонент и, соответственно, новый экземпляр "синглтона".
Важные выводы и нюансы
-
Иерархия компонентов: Если
ActivityComponentявляется подкомпонентомApplicationComponent, то зависимость, помеченная@SingletonвApplicationComponent, будет единой для всех Activity.ActivityComponentбудет запрашивать её у родительского компонента. В этом случае время жизни действительно равно времени жизни приложения. -
Ленивая инициализация (по умолчанию): Зависимости в Dagger создаются лениво (Lazy initialization) в момент первого обращения к ним через
component.inject(...)или прямой вызов метода-провайдера. Это оптимизирует стартовое время приложения. -
Не путать с аннотацией
@javax.inject.Singleton: Dagger использует именно её. Важно импортировать правильную аннотацию:import javax.inject.Singleton -
Потокобезопасность: Dagger гарантирует потокобезопасное создание синглтонных зависимостей внутри компонента. Первый вызов в любом из потоков инициирует создание, последующие получат уже созданный экземпляр.
Итог: Время жизни зависимости с аннотацией @Singleton в Dagger равно времени жизни компонента, в модуле которого она объявлена. Для создания настоящего синглтона на всё приложение необходимо:
- Пометить зависимость
@Singleton. - Объявить её в модуле компонента, привязанного к
Application(или другому контейнеру с жизненным циклом всего процесса). - Убедиться, что этот компонент создается в
Applicationклассе в единственном экземпляре и не пересоздается.