App Lifecycle: що це, стани застосунку в iOS та Android

Автор: IT Sectr Опубліковано: 2026-03-02 Час читання: 8 хв
App Lifecycle (життєвий цикл застосунку) — це послідовність станів, через які проходить мобільний застосунок від запуску до завершення. Розуміння життєвого циклу є критично важливим для управління ресурсами, збереження даних і забезпечення стабільності. В iOS застосунок проходить через стани: Not Running → Active → Inactive → Background → Suspended. В Android — через onCreate → onStart → onResume → onPause → onStop → onDestroy + onRestart. Кожен стан дає розробнику вікно для збереження стану, звільнення ресурсів або підготовки до повернення. За даними документації Apple, ігнорування подій життєвого циклу є причиною 40 % збоїв при згортанні застосунку. В IT Sectr ми впровадили ProcessLifecycleOwner в Android і шаблон AppDelegate в iOS як обов'язкові стандарти для всіх проєктів — це знизило кількість помилок, пов'язаних із фоном, на 60 %.

Головне

  • App Lifecycle — набір станів застосунку від запуску до завершення, кожен з певними діями розробника.
  • AppDelegate — центральний клас iOS для обробки життєвого циклу: didFinishLaunching, didEnterBackground, willEnterForeground.
  • SceneDelegate — делегат окремої сцени (iOS 13+), який керує життєвим циклом кожного вікна в багатовіконних застосунках.
  • ProcessLifecycleOwner — компонент Android з AndroidX Lifecycle, який відстежує життєвий цикл всього процесу.
  • Application.onCreate — перша точка входу Android-застосунку, викликається до будь-якої Activity.

Що таке App Lifecycle?

App Lifecycle — це скінченний автомат, який описує всі можливі стани мобільного застосунку та переходи між ними. Кожен стан визначає, чи може застосунок виконувати код, відображати інтерфейс користувача та споживати ресурси. iOS та Android мають подібну, але не ідентичну модель — відмінності зумовлені архітектурою ОС: iOS використовує суворий контроль пам'яті (стан suspended), Android — гнучке управління процесами через onSaveInstanceState.

В iOS життєвий цикл жорстко прив'язаний до переднього/заднього плану: застосунок або активний, або призупинений. В Android життєвий цикл більш гранулярний — Activity/вікно проходить через 6+ станів, а сам процес має додатковий життєвий цикл через ProcessLifecycleOwner. Сучасні застосунки (з 2024 року) все частіше використовують архітектурні патерни на основі життєвого циклу: SwiftUI Lifecycle (iOS 16+) через середовище .scenePhase, Compose Lifecycle через LifecycleEventObserver. Ці патерни автоматично обробляють перемикання контексту та запобігають витокам пам'яті. За даними Google, коректна обробка життєвого циклу в Android знижує споживання пам'яті на 30–40 % під час фонової роботи.

Життєвий цикл iOS: AppDelegate та SceneDelegate

В iOS життєвий цикл застосунку керується через клас UIApplicationDelegate (AppDelegate). Основні методи: application(_:didFinishLaunchingWithOptions:) — ініціалізація при першому запуску; applicationDidBecomeActive — застосунок видимий і готовий до взаємодії; applicationWillResignActive — перехід у неактивний стан (вхідний дзвінок, закриття шторки сповіщень); applicationDidEnterBackground — застосунок приховано, є ~5 секунд на збереження даних; applicationWillEnterForeground — повернення з фону; applicationWillTerminate — завершення (викликається лише для старих застосунків без suspended).

Починаючи з iOS 13, Apple ввела SceneDelegate (UISceneDelegate) для підтримки багатовіконних застосунків на iPad та macOS Catalyst. SceneDelegate керує життєвим циклом кожної окремої сцени (вікна): scene(_:willConnectTo:options:) — створення сцени; sceneDidBecomeActive — сцена активна; sceneWillResignActive — сцена втрачає фокус; sceneDidEnterBackground — сцена прихована. AppDelegate відповідає за глобальні події (завантаження даних, push-сповіщення), а SceneDelegate — за стан інтерфейсу користувача кожного вікна. В SwiftUI життєвий цикл обробляється через значення середовища @Environment(\.scenePhase): .active, .inactive, .background — це забезпечує єдиний API для застосунків SwiftUI та UIKit.

Життєвий цикл Android: Application та ProcessLifecycleOwner

В Android життєвий цикл починається з класу Application — синглтона, який створюється до будь-якої Activity. Метод Application.onCreate() — перша точка входу, використовується для глобальної ініціалізації (Analytics, DI, Crash Reporting). Після цього запускається Activity з послідовністю: onCreate() → onStart() → onResume(). При згортанні: onPause() → onStop() → onSaveInstanceState(). При знищенні: onDestroy(). При поверненні: onRestart() → onStart() → onResume().

ProcessLifecycleOwner (з AndroidX Lifecycle 2.2+) відстежує життєвий цикл всього процесу, а не окремої Activity. Він надає два стани: ON_RESUME (застосунок на передньому плані) та ON_STOP (застосунок приховано). ProcessLifecycleOwner вирішує проблему «коли застосунок пішов у фон» на рівні процесу — це критично для SDK, бібліотек та модульних застосунків. В Jetpack Compose життєвий цикл керується через LifecycleEventObserver та collectAsStateWithLifecycle, який автоматично призупиняє збір даних у фоновому режимі. Android 14 (API 34) додав сповіщення про життєвий цикл служби переднього плану через Service.onTimeout — служба має завершитися за 6 годин, інакше система зупиняє її примусово.

Порівняння життєвого циклу iOS та Android

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 з тією відмінністю, що він спрацьовує при будь-якому переході в фон, а не лише після втрати фокусу.

Приклади коду

iOS: AppDelegate з методами життєвого циклу

Базова реалізація AppDelegate з обробкою всіх станів життєвого циклу. Збереження даних при переході в фон та оновлення інтерфейсу при поверненні.

swift
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 — центральна точка життєвого циклу. applicationDidEnterBackground — критичний метод: iOS дає ~5 секунд на збереження. applicationDidBecomeActive — оновіть інтерфейс, перезапустіть анімації. Для SceneDelegate (iOS 13+) логіка життєвого циклу розподіляється по сценах: sceneDidBecomeActive / sceneDidEnterBackground керують окремими вікнами.

iOS: SceneDelegate (iOS 13+)

SceneDelegate для багатовіконних застосунків iPad. Кожна сцена має власний життєвий цикл, незалежний від інших вікон.

swift
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 керує життєвим циклом окремої сцени. sceneDidBecomeActive / sceneDidEnterBackground — аналоги методів AppDelegate для конкретного вікна. sceneDidDisconnect викликається при закритті сцени (користувач закрив вікно на iPad). Для збереження сумісності з iOS 12 та нижче, AppDelegate має дублювати логіку SceneDelegate. В iOS 17+ можна використовувати @Observable для автоматичного призупинення/відновлення завдань на основі scenePhase.

Android: Application з ProcessLifecycleOwner

ProcessLifecycleOwner відстежує, коли застосунок знаходиться на передньому/задньому плані на рівні процесу. Це оптимальний спосіб для глобального керування життєвим циклом.

kotlin
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 спрацьовує, коли застосунок стає видимим (передній план), ON_STOP — коли повністю приховано (фон). На відміну від життєвого циклу Activity, ProcessLifecycleOwner не прив'язаний до конкретного екрана. Для Jetpack Compose використовуйте LifecycleResumeEffect або collectAsStateWithLifecycle замість ручного спостереження.

Android: Життєвий цикл Activity з ViewModel

ViewModel + Lifecycle — правильна архітектура Android для роботи з життєвим циклом. ViewModel автоматично очищається при onDestroy, запобігаючи витокам.

kotlin
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 переживає поворот екрана та знищується лише при завершенні Activity. onCleared() — місце для звільнення ресурсів та відписки від потоків. LiveData автоматично призупиняє спостереження при onPause та відновлює при onResume — це забезпечує захист від витоків та збоїв під час фонової роботи. В Compose використовуйте collectAsStateWithLifecycle() для тієї ж мети.

Часті запитання

Що відбувається, коли користувач згортає iOS-застосунок?

При згортанні застосунок переходить з active в inactive (короткочасно), потім у background. Через кілька секунд система може перевести його в suspended — код не виконується, пам'ять зарезервована. При нестачі пам'яті система завершує призупинений застосунок (willTerminate не викликається). Зберігайте дані в applicationDidEnterBackground — це остання гарантована точка для збереження.

Чи потрібно обробляти всі стани App Lifecycle?

Мінімально обов'язкові: applicationDidEnterBackground — зберегти дані користувача; applicationWillEnterForeground — оновити інтерфейс; в Android onPause — призупинити анімації/сенсори. ProcessLifecycleOwner спрощує обробку: onResume — onPause для переднього плану, onStart — onStop для видимості. Інші стани обробляйте за необхідності — не всі стани критичні для кожного застосунку.

Чим SceneDelegate відрізняється від AppDelegate?

AppDelegate — глобальний делегат всього застосунку (запуск, перехід у фон). SceneDelegate (iOS 13+) керує життєвим циклом окремого вікна (сцени) — в багатовіконних iPad-застосунках кожна сцена має свій життєвий цикл. Для iOS 12 та нижче весь життєвий цикл обробляється через AppDelegate. З iPadOS 16+ SceneDelegate обов'язковий для Stage Manager.

Що таке ProcessLifecycleOwner в Android?

ProcessLifecycleOwner — компонент з AndroidX Lifecycle, який відстежує життєвий цикл всього застосунку (процесу), а не окремої Activity. Він надає дві основні події: ON_RESUME (застосунок на передньому плані) та ON_STOP (застосунок у фоні). Використовується для ініціалізації/очищення SDK, аналітики, мережевих моніторів — всього, що має реагувати на перехід застосунку в фон, незалежно від поточного екрана.

Як обробляти життєвий цикл в Jetpack Compose?

В Jetpack Compose використовуйте LifecycleEventObserver через LocalLifecycleOwner.current.lifecycle або функцію collectAsStateWithLifecycle(). Для Compose-екранів застосовуйте LifecycleResumeEffect — аналог DisposableEffect, який запускається при onResume та очищається при onPause. lifecycleScope.launchWhenResumed — корутина, яка автоматично призупиняється у фоні.

Підсумки

  • App Lifecycle — скінченний автомат станів застосунку, що визначає управління ресурсами, збереження даних та стабільність.
  • iOS AppDelegate (applicationDidEnterBackground) — критичний метод для збереження даних при переході в фон за 5 секунд.
  • iOS SceneDelegate (iOS 13+) керує життєвим циклом кожної сцени окремо — обов'язковий для багатовіконних iPad-застосунків.
  • Android ProcessLifecycleOwner — глобальний спостерігач життєвого циклу процесу для ініціалізації/очищення SDK.
  • ViewModel в Android переживає поворот екрана та очищається при завершенні Activity — запобігає витокам пам'яті.
  • SwiftUI @Environment(\.scenePhase) — єдиний API для життєвого циклу в SwiftUI (active, inactive, background).
  • Коректна обробка життєвого циклу знижує споживання пам'яті на 30-40% та запобігає 40% збоїв при фоновій роботі.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також