Перейти к содержанию
Мобильная разработка

10 вопросов по теме «Android: Компоненты и жизненный цикл» на собеседовании

В этом материале — 10 вопросов из русской колоды RecallDeck по теме «Android: Компоненты и жизненный цикл». Сначала сформулируйте короткий ответ сами, затем откройте подробный разбор и проверьте примеры, ограничения и отказные случаи.

8 мин чтения10 подробных ответовПроверено 24 августа 2026
Главная мысль

Привязывайте платформенное решение к lifecycle, состоянию UI, обратной связи, доступности и цене поддержки для команды.

Вопросы и ответы

10 подробных ответов

01

Назови полный жизненный цикл Activity — какие колбэки и зачем нужен каждый?

Короткий ответ: Три «поднимающих» колбэка — onCreate → onStart → onResume — выводят экран к пользователю; три «опускающих» — onPause → onStop → onDestroy — убирают. onRestart вызывается, когда остановленная Activity снова возвращается на экран.

Подробно:

     onCreate()    ← создан: setContentView, init, чтение savedInstanceState

     onStart()     ← стал видимым

     onResume()    ← на переднем плане, принимает ввод

   [ RESUMED — работает ]

     onPause()     ← потерял фокус (частично перекрыт)

     onStop()      ← полностью не виден  ──onRestart()→onStart() при возврате

     onDestroy()   ← уничтожен (finish или нехватка памяти)
  1. onCreate — единственный обязательный; здесь инфляция layout, инициализация, восстановление из savedInstanceState.
  2. onStart / onStop — граница видимости: регистрируем и снимаем то, что нужно только видимому экрану.
  3. onResume / onPause — граница фокуса и ввода; onPause обязан быть коротким — следующий экран не покажется, пока он не вернётся.
  4. onDestroy — финал; может не прийти при убийстве процесса, поэтому критичное сохраняем раньше.

⚠️ Частая ошибка: считать onDestroy гарантированным местом для сохранения. При process death его не будет — сохраняйте в onSaveInstanceState / onStop.

02

launchMode: standard, singleTop, singleTask, singleInstance — чем отличаются и когда каждый уместен?

Короткий ответ: standard создаёт новый экземпляр всегда; singleTop переиспользует Activity, только если она уже на вершине стека; singleTask держит единственный экземпляр как корень своей задачи; singleInstance — то же, но в отдельной задаче, где эта Activity одна.

Подробно:

launchMode Поведение Когда
standard новый экземпляр на каждый запуск обычные экраны
singleTop переиспользует, если наверху → onNewIntent экран из нотификации/поиска
singleTask один экземпляр, корень задачи, чистит всё над ним точка входа, «главный» экран
singleInstance один экземпляр в собственной задаче звонилка, спец-экраны
  1. onNewIntent — при переиспользовании (singleTop/singleTask) onCreate НЕ вызывается; свежий Intent приходит в onNewIntent, и нужно вызвать setIntent(it).
  2. То же флагами Intent — задаётся динамически: FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_CLEAR_TOP, FLAG_ACTIVITY_SINGLE_TOP.
  3. taskAffinity — определяет, в какую задачу попадёт Activity; вместе с singleTask/singleInstance управляет группировкой в Recents.

⚠️ Частая ошибка: ждать onCreate при singleTop-переиспользовании и читать данные из Intent старого запуска — свежий Intent приходит только в onNewIntent.

03

BroadcastReceiver: статическая и динамическая регистрация — в чём разница и какие ограничения?

Короткий ответ: Статическая регистрация — в манифесте, receiver может сработать, даже когда приложение не запущено. Динамическая — через registerReceiver() в коде, живёт, пока не вызовешь unregisterReceiver(). С Android 8 (API 26) манифест почти нельзя использовать для неявных (implicit) broadcast'ов.

Подробно:

Статическая (манифест) Динамическая (код)
Регистрация <receiver> в манифесте registerReceiver()
Живёт даже без запущенного приложения пока не unregisterReceiver()
Ограничение с API 26 нельзя для implicit привязана к lifecycle
  1. Ограничение Oreo (API 26) — большинство неявных broadcast'ов из манифеста не доставляются; исключения — явные (адресные) и белый список вроде BOOT_COMPLETED.
  2. Динамическую — сниматьregisterReceiver в onStart/onResume, unregister в onStop/onPause, иначе утечка Context.
  3. Альтернативы — фоновая реакция → WorkManager с constraints; внутри приложения LocalBroadcastManager устарел, замена — Flow/StateFlow.

⚠️ Частая ошибка: полагаться на манифест-receiver для CONNECTIVITY_CHANGE — с API 26 он не придёт; регистрируйте динамически или используйте WorkManager.

04

Какие колбэки Activity сработают при повороте экрана, нажатии Home, показе диалога поверх и кнопке Назад?

Короткий ответ: Поворот — полное пересоздание. Home — onPause→onStop без destroy. Диалог поверх (AlertDialog/DialogFragment) — как правило вообще ничего: Activity остаётся RESUMED. Назад (выход) — onPause→onStop→onDestroy с isFinishing == true.

Подробно:

Поворот:  onPause → onStop → onSaveInstanceState → onDestroy
          → onCreate → onStart → onRestoreInstanceState → onResume
Home:     onPause → onStop            (потом onRestart→onStart→onResume)
Back:     onPause → onStop → onDestroy  (isFinishing == true)
Диалог:   — ничего —                  (AlertDialog / DialogFragment)
  1. Поворот (P+, API 28) — onSaveInstanceState вызывается ПОСЛЕ onStop; до Android P — до onStop и без гарантии относительно onPause. onRestoreInstanceState — после onStart.
  2. Home vs Back — оба проходят onStop, но Home не разрушает (isFinishing == false), Back разрушает.
  3. Диалог — это не Activity — AlertDialog рисуется в окне той же Activity, состояние не меняется. А вот прозрачная/диалоговая Activity сверху даёт onPause без onStop (хост частично виден).

⚠️ Частая ошибка: думать, что открытие диалога вызывает onPause. Нет — RESUMED сохраняется; onPause вызовет только другая Activity, вставшая поверх.

05

Почему во фрагменте LiveData нужно наблюдать через viewLifecycleOwner, а не через this?

Короткий ответ: View фрагмента живёт короче самого фрагмента: на бэкстеке onDestroyView уже прошёл, а инстанс фрагмента ещё жив. Если наблюдать LiveData с this (фрагментом), обсервер переживёт View; при возврате создастся новая View и второй обсервер — утечка старой View и двойные обновления.

Подробно:

// ❌ обсервер привязан к фрагменту — переживает View
viewModel.state.observe(this) { render(it) }

// ✓ обсервер снимается в onDestroyView вместе с View
viewModel.state.observe(viewLifecycleOwner) { render(it) }
Fragment: onAttach ─ onCreate ───────────────── onDestroy ─ onDetach
View:              onCreateView ─ onViewCreated … onDestroyView
                   └──── жизнь viewLifecycleOwner ────┘
  1. Два разных owner'а — lifecycle самого фрагмента и lifecycle его View; на бэкстеке первый жив, второй уже мёртв.
  2. viewLifecycleOwner — привязывает подписку к окну onCreateView…onDestroyView и снимает её вовремя.
  3. ViewBinding — по той же причине _binding обнуляют в onDestroyView.

⚠️ Частая ошибка: observe(this) во фрагменте с бэкстеком — при каждом возврате обсерверы копятся поверх свежей View, а старая View течёт.

06

onSaveInstanceState, ViewModel и постоянное хранилище — три уровня сохранения состояния: что где держать?

Короткий ответ: ViewModel держит состояние в памяти и переживает поворот, но НЕ process death. onSaveInstanceState (и SavedStateHandle) кладёт немного данных в Bundle — переживает и поворот, и process death. Постоянное хранилище (DB/DataStore) — для того, что должно жить между запусками.

Подробно:

Уровень Переживает поворот Переживает process death Объём
ViewModel да нет любой (в памяти)
SavedStateHandle / onSaveInstanceState да да маленький (Bundle)
DB / DataStore да да большой, постоянно
class SearchViewModel(state: SavedStateHandle) : ViewModel() {
    // переживёт и поворот, и убийство процесса
    val query = state.getStateFlow("query", "")
}
  1. ViewModel — большой рабочий стейт экрана; чистится в onCleared() при реальном уходе с экрана.
  2. SavedStateHandle — навигационные аргументы, id, текст ввода: то, без чего экран после process death восстановится пустым. Только Parcelable/Serializable, не гигабайты.
  3. DB / DataStore — источник правды, а не «кэш состояния UI».

⚠️ Частая ошибка: складывать всё в ViewModel и удивляться пустому экрану после process death — ViewModel живёт в памяти, а память система забрала.

07

Intent против PendingIntent — в чём разница и зачем с Android 12 обязательны флаги мутабельности?

Короткий ответ: Intent — намерение, которое исполняет ваш собственный процесс. PendingIntent — токен-обёртка, который вы отдаёте чужому процессу (система, AlarmManager, нотификации), чтобы он выполнил действие ОТ ВАШЕГО ИМЕНИ и с вашими правами. С Android 12 (API 31) обязателен явный FLAG_IMMUTABLE или FLAG_MUTABLE.

Подробно:

val intent = Intent(ctx, ReplyReceiver::class.java)
val pi = PendingIntent.getBroadcast(
    ctx, 0, intent,
    PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)   // API 31+: без FLAG_IMMUTABLE / FLAG_MUTABLE — крэш
  1. Чужой процесс, ваши права — нотификация живёт в SystemUI, но по тапу действие исполнится так, будто его запустили вы.
  2. FLAG_IMMUTABLE по умолчанию — безопасно; FLAG_MUTABLE берут только когда получателю правда надо дописать extras (inline-ответы, бабблы).
  3. requestCode + FLAG_UPDATE_CURRENT / FLAG_CANCEL_CURRENT — так система различает и обновляет «одинаковые» PendingIntent.

⚠️ Частая ошибка: ставить FLAG_MUTABLE «на всякий случай». Мутабельный PendingIntent с незаполненным таргетом — дыра: чужое приложение может подменить внутренний Intent.

08

Service, Foreground Service и WorkManager — когда что выбрать и как менялись лимиты фоновой работы по версиям?

Короткий ответ: Обычный Service — для короткой работы, пока приложение живо; с API 26 его нельзя запускать из фона. Foreground Service — работа, видимая пользователю прямо сейчас (плеер, навигация, запись), с обязательным уведомлением. WorkManager — гарантированная отложенная/периодическая работа, переживающая перезапуск устройства.

Подробно:

Версия Что изменилось
API 26 (O) фоновые сервисы и manifest implicit broadcast запрещены; появился startForegroundService
API 31 (S) нельзя стартовать FGS из фона → ForegroundServiceStartNotAllowedException
API 34 (U) обязателен foregroundServiceType, проверка соответствия в рантайме
  1. Правило выбора — нужно сейчас и видимо → FGS; можно потом, но обязательно → WorkManager; фоновая реакция на условие → WorkManager с constraints.
  2. startForegroundService — после него ОБЯЗАН вызвать startForeground(id, notification) в течение ~5 c, иначе ANR/крэш.
  3. WorkManager — сам выбирает JobScheduler под капотом и переживает ребут; для срочного — expedited work (WM 2.7+).

⚠️ Частая ошибка: тянуть тяжёлую фоновую загрузку на обычном Service — с API 26 система его прибьёт; это работа для WorkManager.

09

Как ViewModel переживает поворот экрана? Опиши механизм под капотом.

Короткий ответ: При смене конфигурации Activity действительно пересоздаётся, но перед уничтожением фреймворк вызывает onRetainNonConfigurationInstance и сохраняет объект NonConfigurationInstances с ViewModelStore. Новый экземпляр Activity достаёт тот же store через getLastNonConfigurationInstance — и получает те же ViewModel.

Подробно:

Activity #1 ──поворот──► onDestroy
   │  isChangingConfigurations() == true → store НЕ очищается

NonConfigurationInstances { ViewModelStore }   ← держит фреймворк


Activity #2 ──onCreate──► getLastNonConfigurationInstance()
                          → тот же ViewModelStore → те же ViewModel
  1. ViewModelStore — по сути HashMap<key, ViewModel>; ComponentActivity сам является ViewModelStoreOwner.
  2. isChangingConfigurations() — ключевая развилка: при повороте true, и onDestroy НЕ вызывает store.clear(); при реальном finish falseclear()onCleared() на каждой ViewModel.
  3. Почему не переживает process death — NonConfigurationInstances живёт в памяти процесса; убили процесс — исчез и он. Отсюда и нужен SavedStateHandle.

⚠️ Частая ошибка: думать, что ViewModel «сохраняется системой». Нет — её просто НЕ уничтожают вместе с Activity; переживает только пересоздание внутри живого процесса.

10

Что такое process death, почему после него приложение открывается на пустом экране и как это правильно тестировать?

Короткий ответ: Process death — когда система, пока приложение в фоне, убивает его процесс ради памяти. Стирается вся память: ViewModel, статические поля, DI-синглтоны. При возврате система пересоздаёт последнюю Activity, но её стейт null → пустой или битый экран. Спасает только Bundle: onSaveInstanceState / SavedStateHandle.

Подробно:

Приложение в фоне ──► система убивает процесс (нужна память)
       │  ViewModel, static, синглтоны — стёрты

Пользователь вернулся ──► Activity пересоздаётся с savedInstanceState
   восстановил из Bundle → ок;   надеялся на память → пустой экран
  1. Как тестировать честно — приложение в фон, затем adb shell am kill <package> или красная кнопка terminate в Android Studio; после этого вернуться в приложение.
  2. «Don't keep activities» — НЕ то же самое — она разрушает Activity, но процесс и Application-стейт живы, поэтому баги на статике/синглтонах не ловит; для настоящего process death нужен am kill.
  3. Как чинить — критичные аргументы и ввод в SavedStateHandle; не держать «источник правды» в static-полях.

⚠️ Частая ошибка: восстанавливать экран из синглтона или статического поля — после process death оно пустое. Проверяйте именно убийство процесса, а не поворот.

Источники

Источники и редакционная политика

Материалы RecallDeck сопоставлены с официальной документацией и открытыми публикациями компаний, когда первичный источник доступен. Мы не связаны с упомянутыми работодателями, не публикуем конфиденциальные задания и не продаём места в подборках. Формат найма может меняться — уточняйте его у рекрутера.

От чтения к воспроизведению

Отрепетируйте полный цикл интервью.

RecallDeck возвращает сложные темы по расписанию и помогает удерживать в памяти язык, SQL, архитектуру и поведенческие истории.

Начать подготовку

Продолжить подготовку

Библиотека собеседований RecallDeck

Подробные русские ответы, разборы этапов найма и планы подготовки для российского IT-рынка.

RSS