Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Scope Singleton в Android и Dependency Injection
В контексте Dependency Injection (DI) фреймворков, таких как Dagger или Koin, Singleton — это не просто шаблон проектирования, а конкретный scope (область видимости/жизненного цикла), к которому привязывается время жизни объекта.
Ключевой принцип
Scope Singleton означает, что экземпляр класса создается ровно один раз и существует на протяжении всего жизненного цикла компонента, к которому он привязан. Это отличается от глобального синглтона (object в Kotlin), который живет всё время работы приложения.
Основные варианты Scope в Android
1. Application Scope (Глобальный Singleton)
Объект создается один раз и живет всё время жизни приложения (пока живет Application класс).
- Пример в Dagger:
@Module
class AppModule {
@Singleton
@Provides
fun provideRepository(): Repository {
return RepositoryImpl()
}
}
@Component(modules = [AppModule::class])
@Singleton
interface AppComponent {
fun inject(activity: MainActivity)
}
Здесь Repository будет существовать, пока живет AppComponent (обычно привязан к Application).
2. Activity Scope
Объект живет, пока живет конкретная Activity. Уничтожается вместе с ней.
- Пример в Dagger 2 (с использованием подкомпонентов):
@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class ActivityScope
@Module
class ActivityModule {
@ActivityScope
@Provides
fun providePresenter(): Presenter {
return Presenter()
}
}
@Subcomponent(modules = [ActivityModule::class])
@ActivityScope
interface ActivityComponent {
fun inject(fragment: MyFragment)
}
3. Fragment Scope и другие custom scopes
Аналогично можно создавать scope для Fragment, ViewModel, пользовательской сессии.
Почему Singleton — это Scope?
В Dagger/Hilt аннотация @Singleton — это просто предопределенный scope, который по умолчанию привязан к Application компоненту.
@Singleton≠ вечный глобальный объект. Если компонент (например,ActivityComponent) будет уничтожен, все его синглтонные зависимости также станут недоступны и будут собраны GC.- Главное правило: время жизни объекта не может превышать время жизни его компонента.
Практическое значение
// БЕЗ DI (проблема: тестирование, жесткая связь)
object OldSingletonRepo {
fun getData() {}
}
// С DI и Scope (гибко, тестируемо)
class MyRepository @Inject constructor() {
fun getData() {}
}
// В модуле Dagger/Hilt
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Singleton
@Provides
fun provideRepo(): MyRepository = MyRepository()
}
Ключевые выводы:
- Singleton в DI — это всегда scope, а не просто паттерн.
- Объект живет столько же, сколько и компонент, к которому он привязан.
- В Android чаще всего используют:
@Singletonдля глобальных зависимостей (база данных, API клиент)@ActivityScopedдля зависимостей, нужных только в рамках активити@ViewModelScopedв Hilt для зависимостей ViewModel
- Никогда не смешивайте DI-синглтоны с глобальными
object— это нарушает принцип инверсии зависимостей и усложняет тестирование.
Таким образом, Singleton привязан к scope своего DI-компонента, и именно это определяет его жизненный цикл в современной Android-архитектуре.