← Назад к вопросам

Что такое scope у DI фреймворков?

2.0 Middle🔥 192 комментариев
#Dependency Injection

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Scope в контексте Dependency Injection (DI)

Scope в DI-фреймворках — это концепция, определяющая время жизни (lifetime) и область видимости создаваемых зависимостей. Проще говоря, scope контролирует, как долго существует экземпляр объекта и в каком контексте он переиспользуется между различными компонентами приложения.

Основные цели использования Scope

  • Управление временем жизни: Определяет момент создания и уничтожения объекта.
  • Контроль повторного использования: Указывает, когда нужно создавать новый экземпляр, а когда следует использовать существующий (шаблон Singleton в рамках определенной области).
  • Изоляция состояний: Позволяет изолировать данные в рамках конкретного потока, экрана (Activity/Fragment) или пользовательской сессии.
  • Эффективность: Оптимизирует использование памяти и процессорного времени за счет разумного переиспользования тяжеловесных объектов.

Распространенные типы Scope в Android (на примере Dagger/Hilt)

В Dagger и Hilt (официальная надстройка над Dagger для Android) scope реализуется с помощью аннотаций. Каждая аннотация привязывает жизнь зависимости к жизни компонента (Component), который ее предоставляет.

// Объявление кастомного Scope-аннотации в Dagger
@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class MyCustomScope

// Применение Scope к реализации
@MyCustomScope
@Provides
fun provideHeavyObject(): HeavyObject {
    return HeavyObject()
}

Стандартные scopes в Hilt:

  • @Singleton: Жизнь объекта привязана к жизни Application. Создается один раз и существует всё время работы приложения. Идеален для глобальных зависимостей (Retrofit, база данных, репозиторий).

    @Module
    @InstallIn(SingletonComponent::class)
    object AppModule {
        @Singleton
        @Provides
        fun provideRetrofit(): Retrofit {
            return Retrofit.Builder()
                .baseUrl("https://api.example.com/")
                .build()
        }
    }
    
  • @ActivityScoped: Объект живет до тех пор, пока существует привязанная к нему Activity. Все инъекции в одну и ту же Activity получат один и тот же экземпляр.

    @Module
    @InstallIn(ActivityComponent::class)
    object ActivityModule {
        @ActivityScoped
        @Provides
        fun provideActivityDependency(): MyDependency {
            return MyDependency()
        }
    }
    
  • @ViewModelScoped: Жизнь объекта привязана к конкретному ViewModel. Очень полезен для зависимостей, которые должны переживать изменения конфигурации (поворот экрана) вместе с ViewModel.

    @Module
    @InstallIn(ViewModelComponent::class)
    object ViewModelModule {
        @ViewModelScoped
        @Provides
        fun provideScopedToViewModel(): ViewModelSpecificDep {
            return ViewModelSpecificDep()
        }
    }
    
  • @FragmentScoped / @ViewScoped: Аналогично, но для жизни Fragment или View.

Принцип работы и важные нюансы

  1. Иерархия компонентов: Scopes в Dagger/Hilt строятся на иерархии компонентов. Компонент более высокого уровня (например, SingletonComponent) является родителем для компонента более низкого уровня (например, ActivityComponent). Это означает:
    *   Зависимости, доступные в `SingletonComponent`, могут быть инжектированы в `ActivityComponent`.
    *   Обратное неверно. Зависимость, созданная в `ActivityComponent`, не может быть предоставлена `SingletonComponent`.

  1. Связка Scope и Component: Каждый scope аннотирует определенный тип компонента. Например, аннотация @Singleton может использоваться только в модулях, установленных в SingletonComponent::class.

  2. Отсутствие аннотации (Unscoped): Если зависимость не помечена scope-аннотацией, DI-фреймворк будет создавать новый экземпляр каждый раз, когда она запрашивается. Это поведение по умолчанию.

Пример на практике: Разные Scope для разных задач

Представьте приложение для онлайн-магазина:

  • @Singleton: Retrofit, RoomDatabase, SharedPreferences — создаются один раз.
  • @ActivityScoped: Navigator для управления переходами между экранами в рамках одной Activity.
  • @ViewModelScoped: CartManager для корзины покупок, которая должна сохраняться при повороте экрана конкретного товара.
  • Без Scope (Unscoped): ProductItem — DTO объект, который уникален для каждого элемента в списке.

Вывод: Правильное использование scope — это краеугольный камень эффективной архитектуры Android-приложения с DI. Оно позволяет четко управлять ресурсами, предотвращать утечки памяти (например, не держать ссылку на Activity в синглтоне) и писать предсказуемый, тестируемый код, где жизненные циклы всех объектов находятся под полным контролем разработчика.

Что такое scope у DI фреймворков? | PrepBro