Active — aktivní stav životního cyklu iOS aplikace, ve kterém je aplikace v popředí, přijímá dotykové události a interaguje s uživatelem. Zjišťujeme, jak stav Active funguje, které metody delegáta UIApplicationDelegate jsou za něj zodpovědné a jak správně zpracovávat přechody mezi Active a Inactive ve Swiftu.
Hlavní body
Active — stav životního cyklu mobilní aplikace, ve kterém je aplikace v popředí, zobrazuje se na obrazovce zařízení a aktivně interaguje s uživatelem. V tomto stavu aplikace přijímá všechny dotykové události, stisky kláves, data z akcelerometru a gyroskopu a má plný přístup ke grafickému procesoru pro vykreslování rozhraní.
Na iOS je stav Active součástí pětistavového modelu životního cyklu: Not Running → Inactive → Active → Inactive → Background → Suspended → Not Running. Na Androidu je ekvivalentem stav Activity po volání onResume, kdy je Activity na vrcholu zásobníku a přijímá vstup uživatele. Active je jediný stav, ve kterém je UI plně interaktivní a reaguje na gesta, posouvání, kliknutí a animace.
Systém poskytuje aplikaci ve stavu Active maximální prioritu procesoru a RAM. To znamená, že systém takovou aplikaci při nedostatku zdrojů neukončí — nejprve budou uvolněny procesy na pozadí a pozastavené procesy. Aplikace by však měla zdroje využívat efektivně, aby nevybíjela baterii a nezpůsobovala throttling CPU.
Pro uživatele je Active normální stav práce s aplikací. Uživatel vidí rozhraní, může mačkat tlačítka, vyplňovat formuláře, posouvat seznam. Jakékoli přerušení tohoto stavu (hovor, oznámení, přetažení nahoru pro Control Center) přesune aplikaci do Inactive, poté se může vrátit do Active nebo přejít do Background.
iOS používá UIApplicationMain pro správu stavu. Při přechodu do Active systém volá applicationDidBecomeActive. Pro SwiftUI je analogickým mechanismem sledování scenePhase přes Environment. Android používá onResume jako indikátor aktivity Activity v popředí. Oba přístupy zaručují, že aplikace obdrží oznámení o změně stavu a může přizpůsobit své chování.
| Platforma | Metoda/událost | Swift (UIKit) | SwiftUI | Android (Kotlin) |
|---|---|---|---|---|
| iOS | Přechod do Active | applicationDidBecomeActive | scenePhase == .active | — |
| iOS | Opuštění Active | applicationWillResignActive | scenePhase == .inactive | — |
| Android | Přechod do Active | — | — | onResume() |
| Android | Opuštění Active | — | — | onPause() |
V iOS je stav Active zpracováván přes UIApplicationDelegate. Hlavní metoda — applicationDidBecomeActive(_:). Volá se při prvním spuštění aplikace a při návratu z Inactive. Tato metoda je ideálním místem pro obnovení úloh, které byly pozastaveny při přechodu do Inactive: spuštění animací, obnovení časovačů, restartování senzorů, kontrola aktualizací dat na serveru.
Od iOS 13 společnost Apple představila UISceneDelegate pro podporu více oken na iPadu. V tomto případě je applicationDidBecomeActive nahrazeno sceneDidBecomeActive pro každou scénu. Aplikace podporující pouze jednu obrazovku mohou nadále používat UIApplicationDelegate. Oba přístupy jsou volány v okamžiku, kdy se aplikace nebo scéna stane aktivní.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// Aplikace se stala aktivní — obnovujeme úkoly
func applicationDidBecomeActive(_ application: UIApplication) {
resumeAnimations()
restartTimers()
refreshDataIfNeeded()
startObservingSensors()
}
// Aplikace ztrácí aktivitu — pozastavujeme
func applicationWillResignActive(_ application: UIApplication) {
pauseAnimations()
stopTimers()
saveDraftData()
}
private func resumeAnimations() {
UIView.animate(withDuration: 0.3) {
// Obnovení UI animací
}
}
private func refreshDataIfNeeded() {
let lastRefresh = UserDefaults.standard.object(forKey: "lastRefresh") as? Date ?? .distantPast
if Date().timeIntervalSince(lastRefresh) > 300 {
fetchDataFromServer()
}
}
}Kód ukazuje správné zpracování Active v UIKit. applicationDidBecomeActive obnovuje animace, časovače a kontroluje, zda je potřeba aktualizace dat. applicationWillResignActive pozastavuje vše, co by mohlo spotřebovávat zdroje, a ukládá koncepty. Takový pár metod zaručuje, že aplikace správně reaguje na změnu stavu.
V SwiftUI není AppDelegate — správa stavu probíhá přes Environment<ScenePhase>. Hodnota .active je nastavena, když je scéna v popředí a interaktivní. SwiftUI automaticky restartuje animace a aktualizace při návratu do Active. Vývojář se pouze musí přihlásit k onChange pro provádění vedlejších účinků.
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("Scéna se stala aktivní")
resumeWork()
case .inactive:
print("Scéna se stala neaktivní")
pauseWork()
case .background:
print("Scéna přešla na pozadí")
saveState()
@unknown default:
break
}
}
}
private func resumeWork() {
// Obnovení síťových požadavků, animací
}
private func pauseWork() {
// Pozastavení časově citlivých úloh
}
private func saveState() {
// Uložení stavu aplikace
}
}V SwiftUI je scenePhase jediným zdrojem pravdy o stavu aplikace. onChange umožňuje provádět akce při každém přechodu. Je důležité si pamatovat, že scenePhase je k dispozici pouze na iOS 14+ a ve SwiftUI Lifecycle. Pro UIKit aplikace s obrazovkami SwiftUI použijte přístup s UIApplicationDelegate.
Active lze dosáhnout několika způsoby. První a zřejmý — studený start: uživatel klikne na ikonu, aplikace přejde z Not Running přes Inactive do Active. Druhý — návrat z pozadí: uživatel se přepne zpět do aplikace přes App Switcher, aplikace projde Inactive a stane se Active. Třetí — návrat z dočasného přerušení: uživatel ukončí hovor, zavře Control Center nebo odpoví na oznámení — aplikace se vrátí z Inactive do Active.
Not Running → Inactive → Active — studený start. Background → Inactive → Active — návrat z pozadí. Inactive → Active — návrat z dočasného přerušení. V každém případě je applicationDidBecomeActive voláno, ale kontext se může lišit. Při studeném startu je před Active voláno didFinishLaunchingWithOptions, při návratu z pozadí — willEnterForeground. Vývojář může tyto rozdíly využít k výběru strategie obnovení stavu.
| Scénář | Cesta přechodu | Callbacky iOS | Callbacky Android |
|---|---|---|---|
| Studený start | Not Running → Active | didFinishLaunching → didBecomeActive | onCreate → onStart → onResume |
| Návrat z pozadí | Background → Active | willEnterForeground → didBecomeActive | onRestart → onStart → onResume |
| Návrat ze Suspended | Suspended → Active | willEnterForeground → didBecomeActive | onRestart → onStart → onResume |
| Po přerušení | Inactive → Active | didBecomeActive | onResume |
Důležitá poznámka: při návratu ze Suspended iOS nevolá didFinishLaunchingWithOptions, protože aplikace již byla načtena do paměti. To znamená, že inicializační kód umístěný v této metodě není znovu spuštěn. Vývojáři na to často zapomínají a přesouvají kritickou logiku do applicationWillEnterForeground nebo applicationDidBecomeActive pro oba scénáře.
V Androidu je ekvivalentem Active stav Activity po volání onResume(). Activity je považováno za aktivní, když je v popředí a přijímá vstup uživatele. Tento stav odpovídá vrcholu zásobníku Activity. Pokud se nad ním objeví jiné Activity (i částečně), aktuální Activity přechází do stavu onPause — ekvivalent iOS Inactive.
Klíčový rozdíl Androidu — několik Activity může být aktivních současně v režimu multi-window (split screen, freeform). V tomto případě je Activity, se kterým uživatel interaguje, považováno za aktivní a sousední — za pozastavené (onPause). iOS nepodporuje multi-window na iPhone, pouze na iPadu přes UIScene.
class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
// Aplikace se stala aktivní — obnovujeme úkoly
resumeCameraPreview()
startLocationUpdates()
activateSensors()
}
override fun onPause() {
super.onPause()
// Aplikace ztrácí aktivitu — uvolňujeme zdroje
releaseCamera()
stopLocationUpdates()
deactivateSensors()
}
private fun resumeCameraPreview() {
// Spuštění náhledu kamery (vyžaduje oprávnění)
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()
)
}
}Kód ukazuje zpracování Active v Androidu přes onResume/onPause. onResume obnovuje práci s kamerou, geolokací a senzory — zdroje, které by měly být aktivní pouze když je aplikace viditelná pro uživatele. onPause tyto zdroje uvolňuje, aby nevybíjely baterii. CameraX lifecycle-aware API automaticky zastaví náhled při onPause.
První pravidlo — neprovádějte těžké operace v applicationDidBecomeActive nebo onResume. Načítání dat, parsování JSON, práce s databází — vše by mělo být asynchronní a neblokovat hlavní vlákno. Používejte GCD (DispatchQueue) v iOS a Coroutines v Kotlinu pro úlohy na pozadí. Hlavní vlákno by mělo pouze aktualizovat UI a spouštět asynchronní operace.
Druhé pravidlo — synchronizujte stav při každém návratu do Active. Uživatel mohl změnit nastavení v systémové aplikaci, obdržet push oznámení nebo aktualizovat data v jiné aplikaci. Zkontrolujte aktuálnost mezipaměti při přechodu do Active — možná data zastarala během nepřítomnosti uživatele.
Třetí pravidlo — nespoléhejte se na Active jako jediný stav. Aplikace může přeskočit Active a přejít přímo z Not Running do Background (pokud je spuštěna na pozadí). Na iOS k tomu dochází při spuštění přes push oznámení s možností content-available. Na Androidu — při spuštění přes BroadcastReceiver. Vždy kontrolujte aktuální stav před prováděním UI operací.
Čtvrté pravidlo — používejte Activity Result API na Androidu místo onActivityResult. To umožňuje zpracovávat výsledek volání kamery, galerie nebo oprávnění přímo ve stavu Active bez ztráty dat při opětovném vytvoření Activity. Pro iOS použijte async/await s UIApplication.shared.open pro systémové dialogy.
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 {
// Odložit provedení do návratu do Active
NotificationCenter.default.addObserver(
forName: .appDidBecomeActive,
object: nil,
queue: .main
) { _ in
block()
}
}
}
}
extension Notification.Name {
static let appDidBecomeActive = Notification.Name("appDidBecomeActive")
}Kód ukazuje správce stavu Active, který umožňuje ostatním komponentám aplikace kontrolovat aktuální aktivní stav. performWhenActive buď provede blok okamžitě (pokud je aplikace aktivní), nebo odloží provedení do návratu do Active. To je užitečné pro služby, které musí provést akci poté, co se uživatel vrátí do aplikace.
Často kladené otázky
Metoda je volána pokaždé, když aplikace přechází do aktivního stavu: při prvním spuštění, při návratu z pozadí, po zavření Control Center nebo Notification Center, po ukončení hovoru. V normální relaci může být volána 5–10krát v závislosti na akcích uživatele. Neumísťujte do této metody jednorázovou inicializaci.
Visible — neoficiální termín znamenající, že aplikace je viditelná na obrazovce, ale nemusí přijímat události (například částečně zakrytá jiným oknem na iPadu). Active — oficiální stav, ve kterém je aplikace viditelná i interaktivní. Na iPhone je Visible aplikace vždy Active, na iPadu je možná situace Visible + Inactive.
willEnterForeground je voláno při návratu z pozadí, ale aplikace ještě není aktivní — je v Inactive. didBecomeActive je voláno poté, co se aplikace stala plně interaktivní. Pokud potřebujete provést akci dříve, než uživatel uvidí rozhraní — použijte willEnterForeground. Pokud po zobrazení — didBecomeActive.
Ne. Active předpokládá, že aplikace je v popředí a zobrazuje se na obrazovce. Bez viditelného UI může být aplikace v Background nebo Suspended. Výjimka — iPad multi-window, kde jedno okno může být aktivní a druhé ne, ale obě jsou viditelná. VoiceOver a diktafon toto pravidlo nemění.
Na iOS simulátoru stiskněte Cmd+Shift+H pro přechod na domovskou obrazovku (aplikace přejde do Background), poté znovu klikněte na ikonu aplikace. Použijte Cmd+L pro uzamčení obrazovky (willResignActive) a odemčení (didBecomeActive). Pro testování Inactive vyvolejte Control Center (Cmd+Shift+; pro klávesnici macOS) nebo Notification Center.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také