Как работают scopes в DI?
Что проверяют
Понимаете ли вы, что scope в Dagger и Hilt привязывает экземпляр к жизни компонента, а не работает сам по себе. Следом обычно просят объяснить, чем @ActivityRetainedScoped отличается от @ActivityScoped и откуда в DI берутся утечки.
Как отвечать
Начните с поведения по умолчанию: привязка без scope создаётся заново при каждой инъекции. Аннотация scope говорит компоненту: держи один экземпляр, пока жив ты сам. В Hilt компоненты уже связаны с жизненным циклом Android:
@SingletonвSingletonComponent: один экземпляр на процесс, живёт вместе сApplication;@ActivityRetainedScoped: переживает поворот экрана, умирает при окончательном закрытии Activity;@ViewModelScoped: один экземпляр на ViewModel, общий для всех её зависимостей. Саму ViewModel получают через@HiltViewModelиby viewModels(), а не через scope Activity;@ActivityScoped,@FragmentScoped,@ViewScoped: живут столько же, сколько соответствующий объект, и пересоздаются при смене конфигурации;@ServiceScoped: на время жизни Service.
В чистом Dagger scope это своя аннотация с @Scope, которой помечают и компонент, и привязку, а время жизни определяет тот, кто хранит ссылку на компонент. Dagger проверяет scopes при компиляции: привязка с чужим scope в компоненте не соберётся. В Koin то же выражают через single, factory и scope { scoped { } }.
Добавьте про цену: scoped-привязка оборачивается в DoubleCheck с синхронизацией, поэтому вешать scope на всё подряд не стоит. Для лёгких объектов без состояния есть @Reusable.
Где спотыкаются
Отвечают, что ViewModel надо делать @ActivityScoped. В Hilt у неё свой компонент, а ручная привязка к Activity ломает переживание поворота экрана.
Кладут в @Singleton объект, который держит Activity или View. Это прямая утечка: синглтон живёт весь процесс. Если нужен контекст, берут @ApplicationContext.
Считают, что @Singleton делает класс единственным во всём приложении. Он единственный только внутри своего компонента: создадите в чистом Dagger второй экземпляр компонента, получите второй «синглтон».