Active — starea activă a ciclului de viață al aplicației iOS, în care aceasta se află în prim-plan, primește evenimente tactile și interacționează cu utilizatorul. Aflăm cum funcționează starea Active, ce metode ale delegatului UIApplicationDelegate răspund de ea și cum să gestionăm corect tranzițiile între Active și Inactive în Swift.
Principalele
Active — starea ciclului de viață al aplicației mobile, în care aceasta se află în prim-plan, este afișată pe ecranul dispozitivului și interacționează activ cu utilizatorul. În această stare, aplicația primește toate evenimentele tactile, apăsările de taste, datele de la accelerator și giroscop, și are acces deplin la procesorul grafic pentru randarea interfeței.
Pe iOS, starea Active face parte din modelul cu cinci stări ale ciclului de viață: Not Running → Inactive → Active → Inactive → Background → Suspended → Not Running. Pe Android, echivalentul este starea Activity după apelul onResume, când Activity se află în vârful stivei și primește intrarea utilizatorului. Active este singura stare în care UI este complet interactiv și reacționează la gesturi, derulare, clicuri și animații.
Sistemul oferă aplicației în Active prioritate maximă de procesor și RAM. Aceasta înseamnă că sistemul nu va încheia o astfel de aplicație la lipsă de resurse — mai întâi vor fi descărcate procesele de fundal și cele suspendate. Cu toate acestea, aplicația trebuie să folosească resursele eficient pentru a nu descărca bateria și a nu provoca throttling-ul CPU.
Pentru utilizator, Active este starea normală de lucru cu aplicația. Utilizatorul vede interfața, poate apăsa butoane, completa formulare, derula fluxul. Orice întrerupere a acestei stări (apel, notificare, glisare în sus pentru Control Center) mută aplicația în Inactive, după care poate reveni în Active sau poate trece în Background.
iOS folosește UIApplicationMain pentru gestionarea stării. La trecerea în Active, sistemul apelează applicationDidBecomeActive. Pentru SwiftUI, mecanismul similar este observarea scenePhase prin Environment. Android folosește onResume ca indicator al activității Activity în prim-plan. Ambele abordări garantează că aplicația primește notificarea despre schimbarea stării și își poate adapta comportamentul.
| Platformă | Metodă/eveniment | Swift (UIKit) | SwiftUI | Android (Kotlin) |
|---|---|---|---|---|
| iOS | Trecerea în Active | applicationDidBecomeActive | scenePhase == .active | — |
| iOS | Ieșirea din Active | applicationWillResignActive | scenePhase == .inactive | — |
| Android | Trecerea în Active | — | — | onResume() |
| Android | Ieșirea din Active | — | — | onPause() |
În iOS, starea Active este gestionată prin UIApplicationDelegate. Metoda principală — applicationDidBecomeActive(_:). Este apelată la prima lansare a aplicației și la revenirea din Inactive. Această metodă este locul ideal pentru reluarea sarcinilor care au fost suspendate la trecerea în Inactive: pornirea animațiilor, reluarea timerelor, repornirea senzorilor, verificarea actualizărilor de date pe server.
Din iOS 13, Apple a introdus UISceneDelegate pentru suportul mai multor ferestre pe iPad. În acest caz, applicationDidBecomeActive este înlocuit cu sceneDidBecomeActive pentru fiecare scenă. Aplicațiile care suportă un singur ecran pot continua să folosească UIApplicationDelegate. Ambele abordări sunt apelate în momentul în care aplicația sau scena devine activă.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// Aplicația a devenit activă — reluăm sarcinile
func applicationDidBecomeActive(_ application: UIApplication) {
resumeAnimations()
restartTimers()
refreshDataIfNeeded()
startObservingSensors()
}
// Aplicația pierde activitatea — suspendăm
func applicationWillResignActive(_ application: UIApplication) {
pauseAnimations()
stopTimers()
saveDraftData()
}
private func resumeAnimations() {
UIView.animate(withDuration: 0.3) {
// Reluarea animațiilor UI
}
}
private func refreshDataIfNeeded() {
let lastRefresh = UserDefaults.standard.object(forKey: "lastRefresh") as? Date ?? .distantPast
if Date().timeIntervalSince(lastRefresh) > 300 {
fetchDataFromServer()
}
}
}Codul arată gestionarea corectă a Active în UIKit. applicationDidBecomeActive reia animațiile, timerele și verifică dacă este necesară actualizarea datelor. applicationWillResignActive suspendă tot ce poate consuma resurse și salvează ciorne. O astfel de pereche de metode garantează că aplicația reacționează corect la schimbarea stării.
În SwiftUI nu există AppDelegate — gestionarea stării se face prin Environment<ScenePhase>. Valoarea .active este setată când scena se află în prim-plan și este interactivă. SwiftUI repornește automat animațiile și actualizările la revenirea în Active. Dezvoltatorul trebuie doar să se aboneze la onChange pentru a executa efecte secundare.
import SwiftUI
@main
struct ActiveDemoApp: App {
@Environment(\.scenePhase) private var scenePhase
var body: some Scene {
WindowGroup {
ContentView()
}
.onChange(of: scenePhase) { oldPhase, newPhase in
switch newPhase {
case .active:
print("Scena a devenit activă")
resumeWork()
case .inactive:
print("Scena a devenit inactivă")
pauseWork()
case .background:
print("Scena a intrat în fundal")
saveState()
@unknown default:
break
}
}
}
private func resumeWork() {
// Reluarea cererilor de rețea, animațiilor
}
private func pauseWork() {
// Suspendarea sarcinilor sensibile la timp
}
private func saveState() {
// Salvarea stării aplicației
}
}În SwiftUI, scenePhase este singura sursă de adevăr despre starea aplicației. onChange permite executarea acțiunilor la fiecare tranziție. Este important de reținut că scenePhase este disponibil doar pe iOS 14+ și în SwiftUI Lifecycle. Pentru aplicațiile UIKit cu ecrane SwiftUI, utilizați abordarea cu UIApplicationDelegate.
Active poate fi atins pe mai multe căi. Prima și evidentă — pornirea la rece: utilizatorul apasă pe pictogramă, aplicația trece din Not Running prin Inactive în Active. A doua — revenirea din fundal: utilizatorul se întoarce în aplicație prin App Switcher, aplicația trece prin Inactive și devine Active. A treia — revenirea dintr-o întrerupere temporară: utilizatorul termină un apel, închide Control Center sau răspunde la o notificare — aplicația revine din Inactive în Active.
Not Running → Inactive → Active — pornire la rece. Background → Inactive → Active — revenire din fundal. Inactive → Active — revenire din întrerupere temporară. În fiecare caz, applicationDidBecomeActive este apelat, dar contextul poate diferi. La pornirea la rece, înainte de Active, este apelat didFinishLaunchingWithOptions, la revenirea din fundal — willEnterForeground. Dezvoltatorul poate folosi aceste diferențe pentru a alege strategia de restaurare a stării.
| Scenariu | Drumul tranziției | Callback-uri iOS | Callback-uri Android |
|---|---|---|---|
| Pornire la rece | Not Running → Active | didFinishLaunching → didBecomeActive | onCreate → onStart → onResume |
| Revenire din fundal | Background → Active | willEnterForeground → didBecomeActive | onRestart → onStart → onResume |
| Revenire din Suspended | Suspended → Active | willEnterForeground → didBecomeActive | onRestart → onStart → onResume |
| După întrerupere | Inactive → Active | didBecomeActive | onResume |
Observație importantă: la revenirea din Suspended, iOS nu apelează didFinishLaunchingWithOptions, deoarece aplicația a fost deja încărcată în memorie. Aceasta înseamnă că codul de inițializare plasat în această metodă nu se execută din nou. Dezvoltatorii uită adesea acest lucru și mută logica critică în applicationWillEnterForeground sau applicationDidBecomeActive pentru ambele scenarii.
În Android, echivalentul Active este starea Activity după apelul onResume(). Activity este considerat activ când se află în prim-plan și primește intrarea utilizatorului. Această stare corespunde vârfului stivei de Activity. Dacă un alt Activity apare deasupra (chiar și parțial), Activity-ul curent trece în starea onPause — echivalentul iOS Inactive.
Diferența cheie în Android — mai multe Activity pot fi active simultan în modul multi-window (split screen, freeform). În acest caz, Activity-ul cu care utilizatorul interacționează este considerat activ, iar cel vecin — suspendat (onPause). iOS nu suportă multi-window pe iPhone, doar pe iPad prin UIScene.
class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
// Aplicația a devenit activă — reluăm sarcinile
resumeCameraPreview()
startLocationUpdates()
activateSensors()
}
override fun onPause() {
super.onPause()
// Aplicația pierde activitatea — eliberăm resursele
releaseCamera()
stopLocationUpdates()
deactivateSensors()
}
private fun resumeCameraPreview() {
// Pornirea previzualizării camerei (necesită permisiuni)
cameraProvider?.unbindAll()
cameraProvider?.bindToLifecycle(
this,
cameraSelector,
preview,
imageAnalyzer
)
}
private fun startLocationUpdates() {
val locationRequest = LocationRequest.Builder(
Priority.PRIORITY_HIGH_ACCURACY, 5000
).build()
locationClient.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
}
}Codul arată gestionarea Active în Android prin onResume/onPause. onResume reia lucrul cu camera, geolocația și senzorii — resurse care ar trebui să fie active doar când aplicația este vizibilă utilizatorului. onPause eliberează aceste resurse pentru a nu consuma bateria. CameraX lifecycle-aware API oprește automat previzualizarea la onPause.
Prima regulă — nu executați operații grele în applicationDidBecomeActive sau onResume. Încărcarea datelor, parsarea JSON, lucrul cu baza de date — toate acestea ar trebui să fie asincrone și să nu blocheze firul principal. Utilizați GCD (DispatchQueue) în iOS și Coroutines în Kotlin pentru sarcini de fundal. Firul principal ar trebui doar să actualizeze UI și să lanseze operații asincrone.
A doua regulă — sincronizați starea la fiecare revenire în Active. Utilizatorul ar fi putut schimba setările în aplicația de sistem, primi o notificare push sau actualiza datele într-o altă aplicație. Verificați actualitatea cache-ului la trecerea în Active — poate datele au expirat în timpul absenței utilizatorului.
A treia regulă — nu vă bazați pe Active ca singura stare. Aplicația poate sări peste Active și să treacă direct din Not Running în Background (dacă este lansată în fundal). Pe iOS, acest lucru se întâmplă la lansarea printr-o notificare push cu opțiunea content-available. Pe Android — la lansarea prin BroadcastReceiver. Verificați întotdeauna starea curentă înainte de a executa operații UI.
A patra regulă — utilizați Activity Result API pe Android în loc de onActivityResult. Acest lucru permite gestionarea rezultatului apelului camerei, galeriei sau permisiunilor direct în starea Active fără pierdere de date la recrearea Activity. Pentru iOS, utilizați async/await cu UIApplication.shared.open pentru dialogurile sistemului.
import UIKit
final class ActiveStateManager {
static let shared = ActiveStateManager()
private var isActive = false
func setActive(_ active: Bool) {
isActive = active
if active {
NotificationCenter.default.post(name: .appDidBecomeActive, object: nil)
}
}
func performWhenActive(_ block: @escaping () -> Void) {
if isActive {
block()
} else {
// Amână execuția până la revenirea în Active
NotificationCenter.default.addObserver(
forName: .appDidBecomeActive,
object: nil,
queue: .main
) { _ in
block()
}
}
}
}
extension Notification.Name {
static let appDidBecomeActive = Notification.Name("appDidBecomeActive")
}Codul arată un manager al stării Active care permite altor componente ale aplicației să verifice starea activă curentă. performWhenActive fie execută blocul imediat (dacă aplicația este activă), fie amână execuția până la revenirea în Active. Acest lucru este util pentru serviciile care trebuie să execute o acțiune după ce utilizatorul revine în aplicație.
Întrebări frecvente
Metoda este apelată de fiecare dată când aplicația trece în starea activă: la prima lansare, la revenirea din fundal, după închiderea Control Center sau Notification Center, după terminarea unui apel. Într-o sesiune normală poate fi apelată de 5–10 ori în funcție de acțiunile utilizatorului. Nu plasați inițializarea unică în această metodă.
Visible — un termen neoficial care înseamnă că aplicația este vizibilă pe ecran, dar poate să nu primească evenimente (de exemplu, parțial acoperită de o altă fereastră pe iPad). Active — starea oficială în care aplicația este atât vizibilă, cât și interactivă. Pe iPhone, o aplicație Visible este întotdeauna Active, pe iPad este posibilă situația Visible + Inactive.
willEnterForeground este apelat la revenirea din fundal, dar aplicația nu este încă activă — se află în Inactive. didBecomeActive este apelat după ce aplicația a devenit complet interactivă. Dacă trebuie să executați o acțiune înainte ca utilizatorul să vadă interfața — folosiți willEnterForeground. Dacă după afișare — didBecomeActive.
Nu. Active presupune că aplicația se află în prim-plan și este afișată pe ecran. Fără UI vizibil, aplicația poate fi în Background sau Suspended. Excepție — iPad multi-window, unde o fereastră poate fi activă, iar alta nu, dar ambele sunt vizibile. VoiceOver și reportofonul nu schimbă această regulă.
Pe simulatorul iOS, apăsați Cmd+Shift+H pentru a merge la Ecranul de pornire (aplicația trece în Background), apoi faceți clic din nou pe pictograma aplicației. Utilizați Cmd+L pentru blocarea ecranului (willResignActive) și deblocarea (didBecomeActive). Pentru testarea Inactive, apelați Control Center (Cmd+Shift+; pentru tastatura macOS) sau Notification Center.
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