Можно ли использовать Singleton с ViewModel
Что проверяют
Понимаете ли вы, кто владеет жизненным циклом ViewModel и чем это отличается от объекта, живущего всё время процесса. Вопрос двойной: можно ли сделать саму ViewModel синглтоном и можно ли держать в ней ссылку на синглтон. Следом обычно спрашивают, как поделиться данными между двумя экранами.
Как отвечать
Саму ViewModel синглтоном делать нельзя. Её экземпляр живёт в ViewModelStore владельца: активити, фрагмента или записи back stack в Navigation. Она переживает поворот экрана, а когда владелец уходит насовсем, вызывается onCleared() и отменяется viewModelScope. Если держать экземпляр в object или статическом поле, схема ломается:
- мёртвый scope: после первого
onCleared()корутины вviewModelScopeмолча перестают запускаться; - утёкшее состояние: второй экран получает данные, фильтры и ошибки первого;
- утечки памяти: ссылка на
View,Activityили колбэк экрана из глобального объекта держит весь экран в памяти.
А вот зависимость от синглтона внутри ViewModel это нормальная практика. Репозиторий, клиент Retrofit, база Room живут в SingletonComponent Hilt и приходят в @HiltViewModel через @Inject constructor. Условие одно: синглтон не хранит контекст активити, только @ApplicationContext.
Для общих данных между экранами есть штатные варианты: ViewModel на уровне активити через activityViewModels(), на уровне графа навигации через hiltNavGraphViewModels() или navGraphViewModels(), либо общий StateFlow в репозитории-синглтоне.
Где спотыкаются
Отвечают просто «синглтоны это антипаттерн». Интервьюер ждёт различия: синглтон как владелец состояния экрана плох, синглтон как источник данных, выданный через DI, нормален.
Путают переживание поворота с переживанием смерти процесса. Ни ViewModel, ни синглтон не восстанавливаются после того, как система убила процесс, для этого нужен SavedStateHandle или постоянное хранилище.
Создают синглтон вручную через object с lateinit полями. Такой объект сложно подменить в тестах, а инициализация зависит от порядка вызовов. Через Hilt или Koin та же единственность получается без глобального доступа.