Мобильная разработка

Жизненный цикл мобильных приложений

Цели урока

  • Понимать состояния lifecycle (Not Running, Active, Inactive, Background, Suspended) и переходы между ними
  • Применять паттерн: обновление данных в onResume, сохранение в onPause
  • Реализовывать state restoration через SavedStateHandle (Android) и @SceneStorage (iOS)
  • Правильно работать с background tasks: beginBackgroundTask (iOS), WorkManager (Android)

Предварительные знания

  • Нативная vs кроссплатформенная разработка

Черновик письма набирается 10 минут. Звонок. Разговор. Возвращение - черновик исчез. Или навигатор перестроил маршрут, потому что выключился экран. Или банковское приложение потеряло заполненную форму. Всё это - приложения, которые не знали, что ОС может убить их в любой момент. Lifecycle - не абстракция из документации, а правила выживания в среде с ограниченными ресурсами.

  • **Навигаторы** используют background location mode для отслеживания маршрута, даже когда экран выключен
  • **Мессенджеры** получают push notifications через APNs/FCM и будят приложение для обработки входящих сообщений
  • **Банковские приложения** используют state restoration для сохранения заполненных форм перевода при сворачивании

Как мобильные ОС научились убивать приложения

Первый iPhone (2007) вообще не поддерживал сторонние приложения - только веб-приложения через Safari. С iOS 2.0 (2008) появился App Store и нативные приложения, но строгого lifecycle не было. iOS 4 (2010) ввёл multitasking - приложения начали уходить в background. Именно тогда возникли первые проблемы: батарея садилась за 4 часа, потому что разработчики не завершали фоновые задачи. Apple ответила жёсткими ограничениями. Android шёл параллельным путём: Activity lifecycle появился с первыми версиями (2008), но Doze mode, App Standby и фоновые ограничения появились только в Android 6.0 Marshmallow (2015) и ужесточались в каждом релизе.

Lifecycle

**Пользователь набирает длинное сообщение, звонит телефон, после разговора он возвращается - сообщение исчезло.** Это не баг операционной системы. Это следствие того, что разработчик не обработал lifecycle. Мобильная ОС в любой момент может приостановить приложение, отправить в фон или убить при нехватке памяти - lifecycle определяет, через какие состояния проходит приложение и когда вызываются callback-методы.

**Жизненный цикл мобильного приложения** - набор состояний и переходов между ними: - **Not Running** - приложение не запущено - **Active (Foreground)** - на экране, получает события - **Inactive** - видимо, но не получает события (входящий звонок) - **Background** - не видимо, выполняет ограниченные задачи - **Suspended / Terminated** - заморожено или убито ОС

На iOS lifecycle управляется через **UIApplicationDelegate** (или **SwiftUI App** protocol) и **UISceneDelegate**. На Android - через callback-методы **Activity**: onCreate, onStart, onResume, onPause, onStop, onDestroy.

Ключевое различие платформ: на Android каждая Activity имеет свой lifecycle, и система уничтожает Activity при повороте экрана (configuration change). На iOS lifecycle привязан к сценам (scenes), и поворот экрана не уничтожает ViewController.

Что происходит, когда пользователь сворачивает приложение на iOS?

Foreground

**Instagram открывается за 200 мс и сразу показывает свежую ленту.** За этим стоит паттерн: данные кешированы, при переходе в foreground запускается фоновое обновление, UI не блокируется ни на миллисекунду. Foreground - «золотое время» приложения с доступом ко всем ресурсам: сеть, GPU, GPS, камера.

**В foreground приложение может:** - Обновлять UI в реальном времени (60/120 FPS) - Делать сетевые запросы без ограничений - Использовать GPS, камеру, микрофон - Получать touch/gesture события - Воспроизводить аудио/видео **Обязанности в foreground:** - Не блокировать main thread (UI зависнет) - Загружать данные асинхронно - Обрабатывать ошибки сети gracefully

**Главное правило foreground: никогда не блокируй main thread.** Сетевые запросы, обращения к БД, тяжёлые вычисления - всё на background threads. Если main thread заблокирован более 5 секунд, Android покажет диалог «Application Not Responding» (ANR), а iOS может убить приложение.

СобытиеiOS callbackAndroid callback
Приложение стало видимымsceneDidBecomeActiveonResume()
Приложение теряет фокусsceneWillResignActiveonPause()
Появление в окнеviewDidAppearonStart()
Исчезновение из окнаviewDidDisappearonStop()

Типичный паттерн: в onResume/sceneDidBecomeActive - обновляем данные (пользователь мог вернуться спустя часы). В onPause/sceneWillResignActive - сохраняем состояние (пользователь может не вернуться).

Почему нельзя выполнять сетевые запросы на main thread?

Background

**Spotify играет музыку при выключенном экране - это не случайность.** Это явно запрошенный background mode «Audio playback», который iOS разрешает только для конкретных задач. Всё остальное: минимум CPU, запрет обновления UI, 15 секунд на завершение и заморозка. Цель ОС - батарея и память.

**Ограничения в background:** - **iOS:** ~15 секунд на завершение задач, потом приложение замораживается (suspended) - **Android:** Doze mode ограничивает сеть и CPU; WorkManager для отложенных задач - **Обе платформы:** нельзя обновлять UI, ограниченный доступ к GPS **Разрешённые фоновые режимы (iOS):** Audio playback, Location updates, VoIP, Bluetooth, Background fetch, Push notifications

**Push Notifications** - главный механизм «оживления» приложения из фона. Сервер отправляет уведомление через APNs (iOS) или FCM (Android), ОС будит приложение на короткое время для обработки. Так работают мессенджеры, почтовые клиенты и навигаторы.

ЗадачаiOS решениеAndroid решение
Загрузка файлов в фонеURLSession backgroundWorkManager + DownloadManager
Периодическая синхронизацияBGAppRefreshTaskPeriodicWorkRequest
Воспроизведение аудиоAudio background modeForeground Service
Трекинг геолокацииLocation background modeForeground Service + LocationManager
Push-уведомленияAPNs + UNNotificationServiceExtensionFCM + FirebaseMessagingService

Сколько времени iOS даёт приложению на выполнение задач после перехода в background?

State Restoration

**Google Maps возвращает на тот же маршрут даже после перезагрузки телефона.** Это не случайность - state restoration. ОС может убить фоновое приложение в любой момент без предупреждения. Когда пользователь вернётся, он ожидает увидеть то же состояние: открытый экран, введённый текст, позицию скролла.

**State Restoration - зачем нужен:** 1. ОС убивает приложение в фоне (нехватка памяти) 2. Android уничтожает Activity при повороте экрана (configuration change) 3. Пользователь возвращается через часы и ожидает тот же экран **Что сохранять:** текущий экран/навигацию, ввод пользователя (черновики), позицию скролла, фильтры/параметры поиска

На Android проблема острее: **configuration change** (поворот экрана, смена языка, переключение тёмной темы) по умолчанию пересоздаёт Activity. ViewModel переживает configuration change, но не process death. Для полного выживания нужен SavedStateHandle.

СобытиеViewModel жив?SavedState жив?Решение
Поворот экрана (Android)ДаДаViewModel достаточно
Process death (оба)НетДаSavedStateHandle / @SceneStorage
Удаление из Recent AppsНетНетPersistent storage (БД, файлы)
Переустановка приложенияНетНетCloud sync / серверное хранение

Lifecycle мобильного приложения - это постоянная борьба с непредсказуемостью ОС. Приложение может быть убито в любой момент. Хорошее приложение готово к этому: сохраняет состояние, корректно обрабатывает background и возвращает пользователя точно туда, где он остановился.

Приложение живёт вечно в фоне и может делать что угодно

ОС агрессивно ограничивает и убивает фоновые приложения. iOS замораживает через ~15 секунд, Android применяет Doze mode и App Standby Buckets. Приложение должно быть готово к уничтожению в любой момент

Мобильные устройства имеют ограниченную батарею и память. Если бы 50 приложений работали в фоне постоянно, телефон разряжался бы за час. ОС оптимизирует ресурсы, жертвуя фоновыми приложениями.

На Android поворот экрана по умолчанию вызывает:

Ключевые идеи

  • **Lifecycle** - набор состояний (Active, Inactive, Background, Suspended) с callback-методами на каждом переходе
  • **Foreground:** полный доступ к ресурсам, но нельзя блокировать main thread - иначе ANR/зависание
  • **Background:** жёсткие ограничения (~15 с iOS, Doze Android); используй WorkManager/BGTaskScheduler для надёжных задач
  • **State restoration:** ОС может убить приложение без предупреждения; сохраняй состояние через SavedStateHandle/@SceneStorage

Связанные темы

Lifecycle влияет на всё в мобильной разработке:

  • Нативная vs кроссплатформенная — Lifecycle одинаков для всех подходов - даже Flutter/RN приложения проходят через те же состояния ОС
  • Swift и SwiftUI — SwiftUI упрощает lifecycle через @SceneStorage, @Environment(\.scenePhase), но под капотом те же правила iOS

Вопросы для размышления

  • Почему iOS ограничивает фоновое выполнение 15 секундами, а не 5 минутами?
  • Как реализовать оффлайн-режим для мессенджера, учитывая что ОС может убить приложение?
  • Чем подход Android (пересоздание Activity при повороте) лучше или хуже подхода iOS (сохранение ViewController)?

Связанные уроки

  • mob-01 — Нативная vs кроссплатформенная разработка - контекст для понимания lifecycle iOS и Android
  • mob-03 — Swift и SwiftUI используют @SceneStorage и scenePhase - прямо из lifecycle
  • mob-04 — Kotlin и Jetpack Compose строятся на Activity lifecycle как фундаменте
  • se-08 — State management паттерны - ViewModel, SavedState - применяются прямо к lifecycle
  • ds-01 — OS как distributed system: приложение - нода, lifecycle - протокол согласования ресурсов
  • devops-05 — Observability: crashes и ANR из lifecycle - первое что смотрит production monitoring
  • os-03-threads
Жизненный цикл мобильных приложений

0

1

Войти