Inactive — stare de tranziție a ciclului de viață al aplicației între Active și Background, în care aplicația este vizibilă pe ecran, dar nu primește evenimente de atingere. Explicăm cum apare Inactive pe iOS și Android, ce metode delegate răspund pentru el și cum să gestionăm corect întreruperile — apeluri, notificări și gesturi sistemice.
Principalele puncte
Inactive — stare intermediară a ciclului de viață al aplicației mobile care apare la tranziția între Active și Background. În această stare, aplicația se află încă în prim-plan și este vizibilă utilizatorului, dar nu primește evenimente tactile, apăsări de taste sau alte evenimente UI. Sistemul blochează transmiterea evenimentelor către aplicație, dar UI rămâne pe ecran și nu se minimizează.
Natura Inactive este temporară. Această stare durează exact cât durează întreruperea sistemică: de la 0.1 secunde la închiderea rapidă a Control Center până la câteva secunde la un apel primit cu ecran de apel. După terminarea întreruperii, aplicația fie revine în Active, fie trece în Background, dacă utilizatorul a comutat la o altă aplicație. Inactive este singura stare din care este posibilă tranziția în ambele direcții: înapoi în Active sau mai departe în Background.
Pe iOS, Inactive este gestionat automat de sistem. Dezvoltatorul nu poate prelungi sau scurta timpul petrecut în Inactive — este complet controlat de UIApplication. Singurul lucru pe care dezvoltatorul îl poate face este să gestioneze corect intrarea în Inactive prin applicationWillResignActive și revenirea prin applicationDidBecomeActive. Pe Android, analogul este onPause, deși semantica diferă: onPause este apelat chiar și la acoperirea parțială a Activity de către o altă componentă.
Pe iOS, Inactive este o stare separată a ciclului de viață al aplicației (una dintre cele cinci: Not Running, Active, Inactive, Background, Suspended). Pe Android nu există un analog direct — onPause semnalizează că Activity pierde focusul de intrare, dar poate rămâne vizibil (de exemplu, la deschiderea unui dialog). Diferența cheie: Inactive pe iOS este starea aplicației în ansamblu, onPause pe Android este starea unui Activity specific. În modul multi-window pe Android, un Activity poate fi în onPause (fără focus), iar altul în onResume (cu focus).
| Caracteristică | iOS Inactive | Android onPause |
|---|---|---|
| UI vizibil | Da | Da (parțial sau complet) |
| Evenimente tactile | Nu primește | Nu primește |
| Durată | Până la terminarea întreruperii | Până la revenirea focusului sau trecerea în fundal |
| Următoarea stare | Active sau Background | onResume sau onStop |
| Nivel | Aplicație (UIApplication) | Activity |
| Multi-window | O scenă activă | Mai multe Activity în onPause |
Inactive pe iOS apare în câteva scenarii strict definite. Utilizatorul invocă Control Center (deplasare în jos din colțul dreapta sus pe iPhone X+ sau deplasare în sus pe modelele vechi). Utilizatorul deschide Notification Center (deplasare în jos din colțul stânga sus). Sosește un apel primit — sistemul afișează ecranul de apel deasupra aplicației. Se solicită o permisiune sistemică — geolocalizare, microfon, cameră, contacte. Pe iPad, se lansează Slide Over sau Split View — scena activă devine Inactive.
Pe Android, onPause (analogul Inactive) apare într-o gamă și mai largă de situații. Deschiderea unei ferestre de dialog (AlertDialog, DialogFragment). Acoperirea parțială a Activity de către un alt Activity (de exemplu, un Activity transparent pentru autentificare). Rotirea ecranului (Activity este recreat, secvența: onPause → onStop → onDestroy → onCreate → onStart → onResume). Modul multi-window — fereastra inactivă primește onPause. Fiecare dintre aceste evenimente necesită suspendarea operațiilor consumatoare de resurse pentru economisirea bateriei și a performanței.
import UIKit
extension Notification.Name {
static let systemInterruptionBegan = Notification.Name("systemInterruptionBegan")
static let systemInterruptionEnded = Notification.Name("systemInterruptionEnded")
}
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillResignActive(_ application: UIApplication) {
// Aplicația trece în Inactive — întrerupere sistemică
print("Întrerupere: Control Center, apel sau alertă sistemică")
// Suspendarea operațiilor sensibile la timp
pauseVideoPlayback()
stopContinuousDataCollection()
hideSensitiveInformation()
// Notificarea componentelor
NotificationCenter.default.post(name: .systemInterruptionBegan, object: nil)
}
// Revenirea din Inactive în Active
func applicationDidBecomeActive(_ application: UIApplication) {
resumeVideoPlayback()
restartDataCollection()
NotificationCenter.default.post(name: .systemInterruptionEnded, object: nil)
}
private func pauseVideoPlayback() {
// Oprirea videoclipului pentru a nu se suprapune sunetul
}
private func hideSensitiveInformation() {
// Ascunderea datelor sensibile la captura de ecran
// Control Center/App Switcher fac captură de ecran UI
}
}Codul arată gestionarea Inactive în UIKit. applicationWillResignActive oprește videoclipul, întrerupe colectarea datelor și ascunde informațiile sensibile. Acest lucru este important deoarece la deschiderea Control Center sau App Switcher, sistemul face o captură de ecran a UI-ului curent — utilizatorul poate vedea date confidențiale în previzualizare. NotificationCenter permite componentelor aplicației să se aboneze la evenimente de întrerupere.
Pe iOS, Inactive este gestionat de o pereche de metode: applicationWillResignActive (intrarea în Inactive) și applicationDidBecomeActive (revenirea din Inactive). Aceste metode fac parte din UIApplicationDelegate și sunt apelate pentru fiecare tranziție prin Inactive. De la iOS 13 și UISceneDelegate, li s-au adăugat sceneWillResignActive și sceneDidBecomeActive pentru scenarii multi-window.
Pe iPad cu iOS 13+, aplicația poate avea mai multe scene (ferestre). Fiecare scenă are propriul ciclu de viață. O scenă poate deveni Inactive (utilizatorul a comutat la o altă scenă), în timp ce alta rămâne Active. Aceasta este o diferență importantă față de iPhone, unde Inactive este o stare globală pentru întreaga aplicație. La dezvoltarea pentru iPad, Inactive trebuie gestionat separat pentru fiecare scenă.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
// Scena devine inactivă
func sceneWillResignActive(_ scene: UIScene) {
// Pe iPad, această scenă pierde focusul, dar altele pot fi active
print("Scena pierde activitatea")
// Suspendarea sarcinilor acestei scene
pauseSceneSpecificOperations()
}
// Scena devine activă
func sceneDidBecomeActive(_ scene: UIScene) {
print("Scena a devenit activă")
resumeSceneSpecificOperations()
}
private func pauseSceneSpecificOperations() {
// Suspendarea operațiilor specifice acestei scene
}
private func resumeSceneSpecificOperations() {
// Reluarea operațiilor la revenirea focusului
}
}
// AppDelegate rămâne punct de intrare, delegă scenelor
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
return UISceneConfiguration(
name: "Default Configuration",
sessionRole: connectingSceneSession.role
)
}
}Codul arată SceneDelegate pentru gestionarea Inactive la nivel de scenă. sceneWillResignActive este apelat când o anumită fereastră pierde focusul — acest lucru poate apărea la comutarea între ferestre pe iPad. AppDelegate configurează UISceneConfiguration pentru suport multi-window. Fiecare scenă are o stare independentă, iar dezvoltatorul trebuie să le gestioneze separat.
Pe Android, analogul direct al Inactive iOS este metoda onPause() a ciclului de viață al Activity. Este apelată când Activity pierde focusul de intrare, dar poate rămâne vizibil. Scenarii tipice: deschiderea unei ferestre de dialog, lansarea unui alt Activity în aceeași aplicație, un apel primit, apăsarea butonului Home sau Recents. În onPause, dezvoltatorul trebuie să suspende operațiile consumatoare de resurse — animații, redare video, lucrul cu camera.
O diferență importantă pe Android — onPause precedă întotdeauna onStop, dar inversul nu este valabil. Activity poate primi onPause fără onStop (de exemplu, la deschiderea unui Activity transparent). De asemenea, onPause poate fi apelat de mai multe ori pe durata vieții Activity — la fiecare schimbare de focus. Nu plasați logică unică în onPause — folosiți onStop pentru operații finale și onPause doar pentru suspendarea acțiunilor interactive.
class VideoPlayerActivity : AppCompatActivity() {
private var exoPlayer: ExoPlayer? = null
private var currentPosition: Long = 0L
override fun onPause() {
super.onPause()
// Aplicația pierde focusul — oprim videoclipul
exoPlayer?.let { player ->
if (player.isPlaying) {
currentPosition = player.currentPosition
player.pause()
}
}
// Ascundem datele sensibile (GDPR/ecrane bancare)
if (window.decorView.systemUiVisibility and
View.SYSTEM_UI_FLAG_SECURE == 0
) {
hideSensitiveOverlay()
}
}
override fun onResume() {
super.onResume()
// Revenirea focusului — reluăm redarea
exoPlayer?.seekTo(currentPosition)
exoPlayer?.play()
showSensitiveOverlay()
}
private fun hideSensitiveOverlay() {
// Suprapunem un ecran negru peste datele financiare
}
}Codul arată gestionarea corectă a onPause pentru un player video. ExoPlayer este suspendat la pierderea focusului, iar poziția de redare este salvată. La revenirea în onResume, playerul reia redarea de la poziția salvată. În plus, este arătat modelul de ascundere a datelor sensibile — important pentru aplicațiile financiare și medicale care necesită protecție împotriva capturilor de ecran la comutare.
Prima regulă — ascundeți datele confidențiale la trecerea în Inactive. Când utilizatorul deschide Control Center sau App Switcher, iOS face o captură de ecran a ecranului curent. Pe Android, similar — sistemul arată previzualizarea ultimului Activity în Recents. Folosiți UIApplication.shouldSnapshotSecureApp (iOS 16+) sau FLAG_SECURE (Android) pentru protejarea ecranelor confidențiale.
A doua regulă — suspendați animațiile și media. Inactive nu este cel mai bun moment pentru redarea video sau animații, deoarece utilizatorul nu le vede. Mai mult, redarea în fundal poate duce la suprapunerea sunetelor peste sunetele sistemice (apel, notificare). Opriți AVPlayer, ExoPlayer și UIView.animate la intrarea în Inactive și reluați la revenirea în Active.
A treia regulă — blocați introducerea datelor. Dacă aplicația conține formulare de introducere sau schițe, blocați tastatura și câmpurile de intrare la intrarea în Inactive. Acest lucru previne introducerea accidentală la revenire și protejează împotriva interceptării datelor prin suprapuneri sistemice. Pe iOS, dezactivați first responder (view.endEditing(true)), pe Android — ștergeți focusul (currentFocus?.clearFocus()).
A patra regulă — nu efectuați operații lungi în applicationWillResignActive sau onPause. Aceste metode trebuie să se finalizeze în fracțiuni de secundă. Dacă trebuie să salvați un volum mare de date, începeți salvarea într-un fir de execuție în fundal și finalizați-o în applicationDidEnterBackground sau onStop. iOS oferă 5 secunde pentru executarea applicationWillResignActive, după care sistemul poate încheia forțat aplicația.
import UIKit
final class SecureOverlayManager {
private var blurView: UIVisualEffectView?
func showBlurOverlay() {
guard let window = UIApplication.shared.keyWindow,
blurView == nil
else { return }
let blur = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
blur.frame = window.bounds
blur.autoresizingMask = [.flexibleWidth, .flexibleHeight]
window.addSubview(blur)
blurView = blur
}
func removeBlurOverlay() {
blurView?.removeFromSuperview()
blurView = nil
}
}
// Utilizare în AppDelegate
func applicationWillResignActive(_ application: UIApplication) {
SecureOverlayManager().showBlurOverlay()
}
func applicationDidBecomeActive(_ application: UIApplication) {
SecureOverlayManager().removeBlurOverlay()
}Codul arată implementarea unei suprapuneri sigure pentru protejarea datelor la trecerea în Inactive. UIVisualEffectView cu efect de blur este plasat deasupra întregului UI la intrarea în Inactive și eliminat la revenirea în Active. Acest lucru garantează că datele confidențiale nu vor fi vizibile în capturile de ecran App Switcher și Control Center. Similar, se poate folosi UIImageView cu un logo pentru o suprapunere branduită.
Întrebări frecvente
Da. Inactive este o stare intermediară obligatorie înainte de trecerea în Background pe iOS. Aplicația nu poate trece direct din Active în Background — mai întâi devine Inactive, apoi Background. Pe Android, similar: onPause este întotdeauna apelat înainte de onStop. Acest lucru oferă dezvoltatorului posibilitatea de a pregăti datele pentru salvare înainte de a trece complet în fundal.
Da. Pe iPad la lansarea Slide Over sau Split View, scena activă devine Inactive, deși nu are loc nicio întrerupere sistemică — utilizatorul interacționează pur și simplu cu o altă scenă. Aceasta este o caracteristică multi-window a iPadOS. Pe iPhone, Inactive este întotdeauna cauzat de o întrerupere sistemică — apel, notificare, Control Center sau Notification Center.
De obicei între 0.1 și 2 secunde. La un apel primit cu ecran de apel — până la 30 de secunde (până când utilizatorul răspunde sau respinge apelul). iOS nu limitează forțat timpul în Inactive, dar sistemul poate încheia aplicația dacă nu răspunde la evenimente (watchdog). Pe Android, onPause nu are limită de timp, dar se recomandă finalizarea lucrului în 200 ms.
ScenePhase.inactive — valoarea enum ScenePhase, setată când scena se află în prim-plan dar nu primește evenimente. În SwiftUI, o puteți observa prin @Environment(\.scenePhase) și reacționa prin onChange. La trecerea din .active în .inactive, suspendați timer-ele și animațiile. La revenirea în .active — reluați. La trecerea în .background — salvați starea.
Nu, doar pentru aplicațiile care lucrează cu date confidențiale: bancare, medicale, corporative, mesagerii cu chat-uri private. Pentru jocuri și aplicații de divertisment, ascunderea UI nu este necesară. Cu toate acestea, suspendarea jocului și a sunetului la Inactive este o bună practică pentru a evita suprapunerea sunetelor peste notificările sistemice. Apple recomandă ascunderea datelor sensibile, dar nu o impune.
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