Главно
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(
_ 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 апликација се прекида (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. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође