Жизненный цикл спрашивают на любом Android-собесе, даже если проект целиком на Compose. Важно не только перечислить колбэки, но и объяснить, что происходит при повороте, сворачивании и смерти процесса.
Колбэки Activity
onCreate → onStart → onResume → [работает] → onPause → onStop → onDestroy
onCreate(savedInstanceState): один раз на экземпляр. ЗдесьsetContent { }илиsetContentView, получение ViewModel, подписки.savedInstanceStateнеnull, если Activity восстанавливается.onStart: Activity видна пользователю (но может быть не в фокусе).onResume: на переднем плане, получает ввод. Здесь запускают камеру, датчики.onPause: теряет фокус (сверху диалог-Activity, многооконный режим, начало перехода). Должен быть быстрым: следующая Activity не станет активной, пока он не закончится.onStop: больше не видна. Здесь отпускают тяжёлые ресурсы, останавливают обновления UI.onDestroy: экземпляр уничтожается: пользователь закрыл экран, вызванfinish()или пересоздание из-за смены конфигурации.onRestart: передonStart, если Activity возвращается из остановленного состояния.
Система не гарантирует вызов onDestroy, когда убивает процесс: процесс просто завершается. Сохранять важные данные в onDestroy нельзя.
Переход между двумя Activity
Когда A открывает B: A.onPause → B.onCreate → B.onStart → B.onResume → A.onStop. Поэтому onPause должен быть быстрым, а сохранение данных лучше делать в onStop.
При нажатии «Назад» на B: B.onPause → A.onRestart → A.onStart → A.onResume → B.onStop → B.onDestroy.
Смена конфигурации
Поворот, смена языка, тёмной темы, размера окна по умолчанию пересоздают Activity: onPause → onStop → onDestroy → новый экземпляр onCreate → onStart → onResume. Что переживает:
ViewModel: хранится вViewModelStore, который переносится в новый экземпляр;- состояние View с
idи всё, что положили вonSaveInstanceState(Bundle); - в Compose:
rememberSaveable; обычныйrememberтеряется.
Флаг android:configChanges в манифесте отключает пересоздание для указанных изменений, тогда вызывается onConfigurationChanged. Это оправдано для игр и видео, но в обычном приложении маскирует ошибки сохранения состояния. С Android 16 на больших экранах приложения с targetSdk 36 больше не могут запретить поворот и изменение размера, поэтому код должен корректно переживать пересоздание.
Смерть процесса
В фоне система может убить процесс ради памяти. Когда пользователь вернётся, Android пересоздаст стек экранов и передаст сохранённый Bundle. ViewModel при этом не переживёт: она жила в памяти процесса. Выживает только то, что в onSaveInstanceState или SavedStateHandle, и персистентные данные (база, DataStore).
Проверить: свернуть приложение, adb shell am kill <package>, вернуться. Или включить «Don't keep activities» в настройках разработчика (это пересоздание Activity, а не смерть процесса, но много ошибок ловит).
onSaveInstanceState вызывается после onStop (на Android 9+). Bundle хранится в системном процессе и передаётся через Binder, поэтому он должен быть маленьким: превышение лимита транзакции (около 1 МБ на все транзакции процесса) даёт TransactionTooLargeException. Списки и картинки туда не кладут.
Fragment
У фрагмента свой цикл и отдельный цикл view:
onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume
→ onPause → onStop → onDestroyView → onDestroy → onDetach
Фрагмент живёт дольше своей view: при уходе в back stack вызывается onDestroyView, но не onDestroy. Поэтому:
- подписки, которые трогают view, делают на
viewLifecycleOwner, а не наthis; - ссылку на ViewBinding обнуляют в
onDestroyView, иначе утечка всей иерархии view.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.state.collect { render(it) }
}
}
}
Lifecycle-aware компоненты
Lifecycle из AndroidX описывает состояния (INITIALIZED, CREATED, STARTED, RESUMED, DESTROYED) и события (ON_CREATE...ON_DESTROY). Свои компоненты подписываются через DefaultLifecycleObserver и сами реагируют на старт и стоп, вместо того чтобы Activity вызывала их вручную. ProcessLifecycleOwner даёт цикл всего приложения (ушло в фон или вернулось).
Launch modes и задачи
standard (новый экземпляр каждый раз), singleTop (если уже наверху, вызывается onNewIntent), singleTask (один экземпляр в задаче, выше него всё очищается), singleInstance. В Compose-приложениях обычно одна Activity, и навигация внутри неё, поэтому этот вопрос стал реже, но на собесе встречается.
Частые ошибки
- Хранить состояние в полях Activity и терять его при повороте.
- Тяжёлая работа в
onPause. - Подписка на LiveData/Flow во фрагменте через
thisвместоviewLifecycleOwner: дубли обработчиков после возврата из back stack. - Большие объекты в Bundle и
TransactionTooLargeException. - Путать пересоздание при повороте и смерть процесса.
Что спросят на собесе
- Перечисли колбэки Activity и что в каком делать.
- Порядок колбэков при переходе A → B и при повороте.
- Что переживает поворот, а что смерть процесса?
- Чем жизненный цикл фрагмента отличается от цикла его view?
- Зачем
viewLifecycleOwnerиrepeatOnLifecycle?