Главное
App Lifecycle — конечный автомат, описывающий все возможные состояния мобильного приложения и переходы между ними. Каждое состояние определяет, может ли приложение выполнять код, отображать UI и потреблять ресурсы. iOS и Android имеют схожую, но не идентичную модель — различия обусловлены архитектурой ОС: iOS использует строгий контроль памяти (suspended-состояние), Android — гибкое управление процессами через onSaveInstanceState.
В iOS lifecycle жёстко привязан к foreground/background: приложение либо активно, либо приостановлено. В Android lifecycle более гранулярный — Activity/Window проходит через 6+ состояний, а сам процесс имеет дополнительный lifecycle через ProcessLifecycleOwner. Современные приложения (с 2024 года) всё чаще используют архитектурные паттерны на основе lifecycle: SwiftUI Lifecycle (iOS 16+) через .scenePhase environment, Compose Lifecycle через LifecycleEventObserver. Эти паттерны автоматически обрабатывают переключение контекста и предотвращают утечки памяти. По данным Google, корректная обработка lifecycle в Android снижает потребление памяти на 30–40 % при фоновой работе.
В iOS lifecycle приложения управляется через класс UIApplicationDelegate (AppDelegate). Основные методы: application(_:didFinishLaunchingWithOptions:) — инициализация при первом запуске; applicationDidBecomeActive — приложение видимо и готово к взаимодействию; applicationWillResignActive — переход в неактивное состояние (входящий звонок, закрытие шторки); applicationDidEnterBackground — приложение скрыто, есть ~5 секунд на сохранение данных; applicationWillEnterForeground — возвращение из фона; applicationWillTerminate — завершение (вызывается только для старых приложений без suspended).
Начиная с iOS 13, Apple ввела SceneDelegate (UISceneDelegate) для поддержки многоконных приложений на iPad и macOS Catalyst. SceneDelegate управляет lifecycle каждой отдельной сцены (окна): scene(_:willConnectTo:options:) — создание сцены; sceneDidBecomeActive — сцена активна; sceneWillResignActive — сцена теряет фокус; sceneDidEnterBackground — сцена скрыта. AppDelegate при этом отвечает за глобальные события (загрузка данных, пуш-уведомления), а SceneDelegate — за состояние UI каждого окна. В SwiftUI lifecycle обрабатывается через environment-значение @Environment(\.scenePhase): .active, .inactive, .background — это даёт единый API для SwiftUI и UIKit приложений.
В Android lifecycle начинается с класса Application — синглтона, который создаётся до любой Activity. Метод Application.onCreate() — первая точка входа, используется для глобальной инициализации (Analytics, DI, Crash Reporting). После этого запускается Activity с последовательностью: onCreate() → onStart() → onResume(). При сворачивании: onPause() → onStop() → onSaveInstanceState(). При уничтожении: onDestroy(). При возвращении: onRestart() → onStart() → onResume().
ProcessLifecycleOwner (из AndroidX Lifecycle 2.2+) отслеживает lifecycle всего процесса, а не отдельной Activity. Он предоставляет два состояния: ON_RESUME (приложение в foreground) и ON_STOP (приложение скрыто). ProcessLifecycleOwner решает проблему «когда приложение ушло в фон» на уровне процесса — это критично для SDK, библиотек и модульных приложений. В Jetpack Compose lifecycle управляется через LifecycleEventObserver и collectAsStateWithLifecycle, который автоматически приостанавливает сбор данных при фоновом режиме. Android 14 (API 34) добавил уведомление о foreground service lifecycle через Service.onTimeout — сервис должен завершиться за 6 часов, иначе система останавливает его принудительно.
| iOS | Android | Описание |
|---|---|---|
| Not Running | — | Приложение не запущено |
| didFinishLaunching | Application.onCreate | Первая инициализация при запуске |
| Active | onResume | Приложение видимо и принимает ввод |
| Inactive | onPause | Временная потеря фокуса (звонок, шторка) |
| Background | onStop | Приложение скрыто, код может выполняться |
| Suspended | — | Код не выполняется, память зарезервирована |
| Will Terminate | onDestroy | Приложение завершается |
Основное различие: iOS принудительно переводит приложение в Suspended (код не выполняется) через 5-10 секунд после ухода в фон. Android позволяет фоновую работу (сервисы, WorkManager) в течение более длительного времени, но с ограничениями Doze Mode (Android 6+) и фоновых ограничений (Android 12+). ProcessLifecycleOwner в Android — аналог UIApplicationDidEnterBackgroundNotification в iOS с тем отличием, что он срабатывает при любом переходе в фон, а не только после потери фокуса.
Базовая реализация AppDelegate с обработкой всех состояний жизненного цикла. Сохранение данных при переходе в фон и обновление UI при возвращении.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
Analytics.shared.initialize()
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
NotificationCenter.default.post(name: .appDidBecomeActive, object: nil)
}
func applicationWillResignActive(_ application: UIApplication) {
NotificationCenter.default.post(name: .appWillResignActive, object: nil)
}
func applicationDidEnterBackground(_ application: UIApplication) {
CoreDataManager.shared.saveContext()
UserDefaults.standard.synchronize()
}
func applicationWillEnterForeground(_ application: UIApplication) {
NetworkManager.shared.refreshSession()
}
}
AppDelegate — центральная точка lifecycle. applicationDidEnterBackground — критический метод: iOS даёт ~5 секунд на сохранение. applicationDidBecomeActive — обновите UI, перезапустите анимации. Для SceneDelegate (iOS 13+) логика lifecycle разносится по сценам: sceneDidBecomeActive / sceneDidEnterBackground управляют отдельными окнами.
SceneDelegate для многоконных приложений iPad. Каждая сцена имеет собственный lifecycle, независимый от других окон.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
}
func sceneDidBecomeActive(_ scene: UIScene) {
PlayerManager.shared.resume()
}
func sceneDidEnterBackground(_ scene: UIScene) {
PlayerManager.shared.pause()
CoreDataManager.shared.saveContext()
}
func sceneDidDisconnect(_ scene: UIScene) {
PlayerManager.shared.cleanup()
}
}
SceneDelegate управляет lifecycle отдельной сцены. sceneDidBecomeActive / sceneDidEnterBackground — аналог AppDelegate-методов для конкретного окна. sceneDidDisconnect вызывается при закрытии сцены (пользователь закрыл окно на iPad). Для сохранения совместимости с iOS 12 и ниже, AppDelegate должен дублировать SceneDelegate-логику. В iOS 17+ можно использовать @Observable для автоматической приостановки/возобновления задач на основе scenePhase.
ProcessLifecycleOwner отслеживает, когда приложение находится в foreground/background на уровне процесса. Это оптимальный способ для глобального lifecycle-менеджмента.
import android.app.Application
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver())
}
}
class AppLifecycleObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onEnterForeground() {
Analytics.shared.onForeground()
NetworkMonitor.shared.start()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onEnterBackground() {
Analytics.shared.onBackground()
NetworkMonitor.shared.stop()
}
}
ProcessLifecycleOwner — единственный корректный способ отследить переход в фон на уровне приложения. ON_START срабатывает, когда приложение становится видимым (foreground), ON_STOP — когда полностью скрыто (background). В отличие от Activity lifecycle, ProcessLifecycleOwner не привязан к конкретному экрану. Для Jetpack Compose используйте LifecycleResumeEffect или collectAsStateWithLifecycle вместо ручного наблюдения.
ViewModel + Lifecycle — правильная архитектура Android для работы с lifecycle. ViewModel автоматически очищается при onDestroy, предотвращая утечки.
import androidx.lifecycle.ViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
class TimerViewModel : ViewModel() {
private val _time = MutableLiveData<Long>()
val time: LiveData<Long> = _time
private var startTime = System.currentTimeMillis()
init {
updateTime()
}
private fun updateTime() {
_time.value = System.currentTimeMillis() - startTime
}
override fun onCleared() {
super.onCleared()
Logger.d("ViewModel cleared — освобождение ресурсов")
}
}
// В Activity
class TimerActivity : AppCompatActivity() {
private val viewModel: TimerViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Logger.d("Activity created")
}
override fun onResume() {
super.onResume()
viewModel.time.observe(this) { Logger.d("Time: $it") }
}
override fun onPause() {
super.onPause()
Logger.d("Activity paused — приостановка анимаций")
}
override fun onDestroy() {
super.onDestroy()
Logger.d("Activity destroyed — очистка")
}
}
ViewModel переживает поворот экрана и уничтожается только при finish() Activity. onCleared() — место для освобождения ресурсов, отписки от потоков. LiveData автоматически приостанавливает наблюдение при onPause и возобновляет при onResume — это даёт защиту от утечек и крашей при фоновой работе. В Compose используйте collectAsStateWithLifecycle() для той же цели.
Часто задаваемые вопросы
При сворачивании приложение переходит из active в inactive (кратковременно), затем в background. Через несколько секунд система может перевести его в suspended — код не выполняется, память зарезервирована. При нехватке памяти suspended-приложениеterminate (willTerminate не вызывается). Сохраняйте данные в applicationDidEnterBackground — это последняя гарантированная точка для сохранения.
Минимально обязательные: applicationDidEnterBackground — сохранить пользовательские данные; applicationWillEnterForeground — обновить UI; в Android onPause — приостановить анимации/сенсоры. ProcessLifecycleOwner упрощает обработку: onResume — onPause для foreground, onStart — onStop для видимости. Остальные состояния обрабатывайте по необходимости — не все состояния критичны для каждого приложения.
AppDelegate — глобальный делегат всего приложения (запуск, переход в фон). SceneDelegate (iOS 13+) управляет lifecycle отдельного окна (сцены) — в многоконных iPad приложениях каждая сцена имеет свой lifecycle. Для iOS 12 и ниже весь lifecycle обрабатывается через AppDelegate. С iPadOS 16+ SceneDelegate обязателен для Stage Manager.
ProcessLifecycleOwner — компонент из AndroidX Lifecycle, который отслеживает lifecycle всего приложения (процесса), а не отдельной Activity. Он предоставляет два основных события: ON_RESUME (приложение в foreground) и ON_STOP (приложение в background). Используется для инициализации/очистки SDK, аналитики, сетевых мониторов — всего, что должно реагировать на переход приложения в фон, независимо от текущего экрана.
В Jetpack Compose используйте LifecycleEventObserver через LocalLifecycleOwner.current.lifecycle или функцию collectAsStateWithLifecycle(). Для Compose-экранов применяйте LifecycleResumeEffect — аналог DisposableEffect, который запускается при onResume и очищается при onPause. lifecycleScope.launchWhenResumed — корутина, автоматически приостанавливаемая в фоне.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также