Основни точки
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 отговаря за глобални събития (зареждане на данни, push известия), а 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(_: UIApplication, didFinishLaunchingWithOptions lo: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Analytics.shared.initialize(); return true }
func applicationDidBecomeActive(_: UIApplication) { NotificationCenter.default.post(name: .appDidBecomeActive, object: nil) }
func applicationWillResignActive(_: UIApplication) { NotificationCenter.default.post(name: .appWillResignActive, object: nil) }
func applicationDidEnterBackground(_: UIApplication) { CoreDataManager.shared.saveContext(); UserDefaults.standard.synchronize() }
func applicationWillEnterForeground(_: 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(_: UIScene, willConnectTo s: UISceneSession, options o: UIScene.ConnectionOptions) {
guard let ws = (_ as? UIWindowScene) else { return }
window = UIWindow(windowScene: ws)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
}
func sceneDidBecomeActive(_: UIScene) { PlayerManager.shared.resume() }
func sceneDidEnterBackground(_: UIScene) { PlayerManager.shared.pause(); CoreDataManager.shared.saveContext() }
func sceneDidDisconnect(_: 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 приложението се прекратява (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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също