Puncte cheie
App Lifecycle — un automat finit de stări care descrie toate stările posibile ale unei aplicații mobile și tranzițiile dintre ele. Fiecare stare determină dacă aplicația poate executa cod, poate afișa UI și poate consuma resurse. iOS și Android au un model similar, dar nu identic — diferențele sunt determinate de arhitectura OS: iOS utilizează control strict al memoriei (starea suspended), Android — gestionare flexibilă a proceselor prin onSaveInstanceState.
În iOS lifecycle este strict legat de foreground/background: aplicația fie este activă, fie suspendată. În Android lifecycle este mai granular — Activity/Window trece prin 6+ stări, iar procesul în sine are un lifecycle suplimentar prin ProcessLifecycleOwner. Aplicațiile moderne (din 2024) folosesc tot mai mult modele arhitecturale bazate pe lifecycle: SwiftUI Lifecycle (iOS 16+) prin .scenePhase environment, Compose Lifecycle prin LifecycleEventObserver. Aceste modele gestionează automat comutarea contextului și previn scurgerile de memorie. Conform Google, procesarea corectă a lifecycle în Android reduce consumul de memorie cu 30–40% în timpul lucrului în fundal.
În iOS lifecycle-ul aplicației este gestionat prin clasa UIApplicationDelegate (AppDelegate). Metodele principale: application(_:didFinishLaunchingWithOptions:) — inițializare la prima lansare; applicationDidBecomeActive — aplicația este vizibilă și gata de interacțiune; applicationWillResignActive — trecerea în stare inactivă (apel primit, închiderea ecranului); applicationDidEnterBackground — aplicația este ascunsă, există ~5 secunde pentru salvarea datelor; applicationWillEnterForeground — revenirea din fundal; applicationWillTerminate — finalizare (apelată doar pentru aplicații vechi fără suspended).
Începând cu iOS 13, Apple a introdus SceneDelegate (UISceneDelegate) pentru suportul aplicațiilor multi-fereastră pe iPad și macOS Catalyst. SceneDelegate gestionează lifecycle-ul fiecărei scene (ferestre): scene(_:willConnectTo:options:) — crearea scenei; sceneDidBecomeActive — scena activă; sceneWillResignActive — scena pierde focalizarea; sceneDidEnterBackground — scena ascunsă. AppDelegate răspunde de evenimentele globale (încărcare date, notificări push), iar SceneDelegate — de starea UI a fiecărei ferestre. În SwiftUI lifecycle-ul este gestionat prin valoarea de mediu @Environment(\.scenePhase): .active, .inactive, .background — acesta oferă o API unificată pentru aplicațiile SwiftUI și UIKit.
În Android lifecycle-ul începe cu clasa Application — un singleton care este creat înainte de orice Activity. Metoda Application.onCreate() — primul punct de intrare, utilizat pentru inițializare globală (Analytics, DI, Crash Reporting). După aceasta, Activity este lansată cu secvența: onCreate() → onStart() → onResume(). La minimizare: onPause() → onStop() → onSaveInstanceState(). La distrugere: onDestroy(). La revenire: onRestart() → onStart() → onResume().
ProcessLifecycleOwner (din AndroidX Lifecycle 2.2+) urmărește lifecycle-ul întregului proces, nu al unei Activity individuale. Oferă două stări: ON_RESUME (aplicația în foreground) și ON_STOP (aplicația ascunsă). ProcessLifecycleOwner rezolvă problema „când aplicația a intrat în fundal" la nivel de proces — acest lucru este critic pentru SDK-uri, biblioteci și aplicații modulare. În Jetpack Compose lifecycle-ul este gestionat prin LifecycleEventObserver și collectAsStateWithLifecycle, care oprește automat colectarea datelor în modul fundal. Android 14 (API 34) a adăugat notificarea despre lifecycle-ul foreground service prin Service.onTimeout — serviciul trebuie să se finalizeze în 6 ore, altfel sistemul îl oprește forțat.
| iOS | Android | Descriere |
|---|---|---|
| Not Running | — | Aplicația nu este pornită |
| didFinishLaunching | Application.onCreate | Inițializare la pornire |
| Active | onResume | Aplicația vizibilă și primește intrări |
| Inactive | onPause | Pierdere temporară a focalizării (apel, ecran) |
| Background | onStop | Aplicația ascunsă, codul poate fi executat |
| Suspended | — | Codul nu se execută, memoria rezervată |
| Will Terminate | onDestroy | Aplicația se închide |
Diferența principală: iOS forțează trecerea aplicației în Suspended (codul nu se execută) la 5-10 secunde după intrarea în fundal. Android permite lucrul în fundal (servicii, WorkManager) pentru o perioadă mai lungă, dar cu restricțiile Doze Mode (Android 6+) și restricțiile de fundal (Android 12+). ProcessLifecycleOwner în Android — analogul UIApplicationDidEnterBackgroundNotification în iOS, cu diferența că se activează la orice trecere în fundal, nu doar după pierderea focalizării.
Implementarea de bază a AppDelegate cu gestionarea tuturor stărilor ciclului de viață. Salvarea datelor la trecerea în fundal și actualizarea UI la revenire.
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 — punctul central al lifecycle-ului. applicationDidEnterBackground — metodă critică: iOS oferă ~5 secunde pentru salvarea datelor. applicationDidBecomeActive — actualizați UI, reporniți animațiile. Pentru SceneDelegate (iOS 13+) logica lifecycle-ului este distribuită pe scene: sceneDidBecomeActive / sceneDidEnterBackground gestionează ferestre individuale.
SceneDelegate pentru aplicații multi-fereastră iPad. Fiecare scenă are propriul lifecycle, independent de celelalte ferestre.
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 gestionează lifecycle-ul unei scene individuale. sceneDidBecomeActive / sceneDidEnterBackground — echivalentul metodelor AppDelegate pentru o fereastră specifică. sceneDidDisconnect este apelată la închiderea scenei (utilizatorul a închis fereastra pe iPad). Pentru păstrarea compatibilității cu iOS 12 și mai vechi, AppDelegate trebuie să dubleze logica SceneDelegate. În iOS 17+ puteți folosi @Observable pentru oprirea/pornirea automată a sarcinilor pe baza scenePhase.
ProcessLifecycleOwner urmărește când aplicația este în foreground/background la nivel de proces. Aceasta este modalitatea optimă pentru gestionarea globală a lifecycle-ului.
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 — singurul mod corect de a urmări trecerea în fundal la nivel de aplicație. ON_START se activează când aplicația devine vizibilă (foreground), ON_STOP — când este complet ascunsă (background). Spre deosebire de Activity lifecycle, ProcessLifecycleOwner nu este legat de un ecran specific. Pentru Jetpack Compose utilizați LifecycleResumeEffect sau collectAsStateWithLifecycle în locul observării manuale.
ViewModel + Lifecycle — arhitectura corectă Android pentru lucrul cu lifecycle. ViewModel se curăță automat la onDestroy, prevenind scurgerile de memorie.
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 — eliberare resurse")
}
}
// În 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 — oprire animații")
}
override fun onDestroy() {
super.onDestroy()
Logger.d("Activity destroyed — curățare")
}
}
ViewModel supraviețuiește rotației ecranului și este distrus doar la finish() Activity. onCleared() — locul pentru eliberarea resurselor, dezabonarea de la fluxuri. LiveData oprește automat observarea la onPause și o reia la onResume — oferind protecție împotriva scurgerilor și crash-urilor în timpul lucrului în fundal. În Compose utilizați collectAsStateWithLifecycle() în același scop.
Întrebări frecvente
La minimizare, aplicația trece din active în inactive (scurt timp), apoi în background. După câteva secunde sistemul o poate trece în suspended — codul nu se execută, memoria este rezervată. La lipsă de memorie, aplicația suspended este terminată (willTerminate nu este apelată). Salvați datele în applicationDidEnterBackground — acesta este ultimul punct garantat pentru salvare.
Minim obligatorii: applicationDidEnterBackground — salvați datele utilizatorului; applicationWillEnterForeground — actualizați UI; în Android onPause — opriți animațiile/senzorii. ProcessLifecycleOwner simplifică procesarea: onResume — onPause pentru foreground, onStart — onStop pentru vizibilitate. Celelalte stări procesați după necesitate — nu toate stările sunt critice pentru fiecare aplicație.
AppDelegate — delegatul global al întregii aplicații (pornire, trecere în fundal). SceneDelegate (iOS 13+) gestionează lifecycle-ul unei ferestre individuale (scenei) — în aplicațiile multi-fereastră iPad fiecare scenă are propriul lifecycle. Pentru iOS 12 și mai vechi, întregul lifecycle este procesat prin AppDelegate. De la iPadOS 16+ SceneDelegate este obligatoriu pentru Stage Manager.
ProcessLifecycleOwner — component din AndroidX Lifecycle care urmărește lifecycle-ul întregii aplicații (procesului), nu al unei Activity individuale. Oferă două evenimente principale: ON_RESUME (aplicația în foreground) și ON_STOP (aplicația în background). Este utilizat pentru inițializarea/curățarea SDK-urilor, analiticii, monitorizării rețelei — tot ce trebuie să reacționeze la trecerea aplicației în fundal, indiferent de ecranul curent.
În Jetpack Compose utilizați LifecycleEventObserver prin LocalLifecycleOwner.current.lifecycle sau funcția collectAsStateWithLifecycle(). Pentru ecranele Compose aplicați LifecycleResumeEffect — analogul DisposableEffect care se lansează la onResume și se curăță la onPause. lifecycleScope.launchWhenResumed — corutină oprită automat în fundal.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și