Как сделать, чтобы Dagger компонент переживал смену конфигураций в Android
Что проверяют
Понимаете ли вы, что компонент Dagger живёт ровно столько, сколько живёт ссылка на него, а при повороте экрана Activity пересоздаётся вместе со всем, что в ней создано. Следом обычно спрашивают, что будет при смерти процесса и как ту же задачу решает Hilt.
Как отвечать
Сначала назовите причину: если компонент собирается в onCreate, после смены конфигурации создаётся новый граф, и все объекты со скоупом экрана теряются. Значит, компонент нужно хранить в объекте, который переживает пересоздание Activity:
Application: там живёт корневойAppComponentсо скоупом@Singleton. Подходит для того, что нужно всему приложению, но не для зависимостей одного экрана;ViewModelкак держатель: сабкомпонент со своим скоупом, например@ScreenScope, создаётся внутриViewModelчерез фабрику изAppComponent. Activity в каждомonCreateполучает ту жеViewModelизViewModelProviderи вызываетcomponent.inject(this). Граф живёт доonCleared(), то есть до настоящего закрытия экрана;- Hilt: всё это уже встроено.
ActivityRetainedComponentсо скоупом@ActivityRetainedScopedпереживает поворот, аViewModelComponentсо скоупом@ViewModelScopedпривязан к жизниViewModel. СамаViewModelпомечается@HiltViewModelи получает зависимости через@Inject constructor.
Старые приёмы вроде setRetainInstance(true) у фрагмента или onRetainCustomNonConfigurationInstance стоит назвать как устаревшие и сказать, что их заменила ViewModel.
Где спотыкаются
Кладут в долгоживущий компонент ссылку на Activity или её Context. После поворота граф держит старую Activity, и получается утечка. В такой компонент можно отдавать только контекст Application.
Внедряют ViewModel с параметрами в конструкторе, но получают её через ViewModelProvider(this) без своей ViewModelProvider.Factory. Стандартная фабрика не умеет вызывать такой конструктор, и приложение падает при открытии экрана.
Путают смену конфигурации со смертью процесса. ViewModel и сохранённый в ней граф при убийстве процесса исчезают, поэтому пользовательское состояние нужно класть в SavedStateHandle.