Active — aktywny stan cyklu życia aplikacji iOS, w którym znajduje się ona na pierwszym planie, odbiera zdarzenia dotykowe i wchodzi w interakcję z użytkownikiem. Dowiedz się, jak działa stan Active, jakie metody delegata UIApplicationDelegate za niego odpowiadają i jak poprawnie obsługiwać przejścia między Active i Inactive w Swift.
Najważniejsze
Active — stan cyklu życia aplikacji mobilnej, w którym znajduje się ona na pierwszym planie, jest wyświetlana na ekranie urządzenia i aktywnie wchodzi w interakcję z użytkownikiem. W tym stanie aplikacja odbiera wszystkie zdarzenia dotykowe, naciśnięcia klawiszy, dane z akcelerometru i żyroskopu, a także ma pełny dostęp do procesora graficznego do renderowania interfejsu.
W iOS stan Active jest częścią pięciostanowego modelu cyklu życia: Not Running → Inactive → Active → Inactive → Background → Suspended → Not Running. W Androidzie odpowiednikiem jest stan Activity po wywołaniu onResume, gdy Activity znajduje się na szczycie stosu i przyjmuje dane wejściowe użytkownika. Active to jedyny stan, w którym UI jest w pełni interaktywny i reaguje na gesty, przewijanie, kliknięcia i animacje.
System zapewnia aplikacji w stanie Active maksymalny priorytet procesora i pamięci RAM. Oznacza to, że system nie zakończy takiej aplikacji przy braku zasobów — najpierw zostaną wyładowane procesy tła i zawieszone. Jednak aplikacja powinna efektywnie wykorzystywać zasoby, aby nie rozładowywać baterii i nie powodować throttlingu CPU.
Dla użytkownika Active to normalny stan pracy z aplikacją. Użytkownik widzi interfejs, może naciskać przyciski, wypełniać formularze, przewijać listę. Każde przerwanie tego stanu (rozmowa, powiadomienie, przesunięcie w górę dla Control Center) przenosi aplikację do Inactive, po czym może ona wrócić do Active lub przejść do Background.
iOS używa UIApplicationMain do zarządzania stanem. Przy przejściu do Active system wywołuje applicationDidBecomeActive. Dla SwiftUI analogicznym mechanizmem jest obserwacja scenePhase przez Environment. Android używa onResume jako wskaźnika aktywności Activity na pierwszym planie. Oba podejścia gwarantują, że aplikacja otrzymuje powiadomienie o zmianie stanu i może dostosować swoje zachowanie.
| Platforma | Metoda/zdarzenie | Swift (UIKit) | SwiftUI | Android (Kotlin) |
|---|---|---|---|---|
| iOS | Przejście do Active | applicationDidBecomeActive | scenePhase == .active | — |
| iOS | Wyjście z Active | applicationWillResignActive | scenePhase == .inactive | — |
| Android | Przejście do Active | — | — | onResume() |
| Android | Wyjście z Active | — | — | onPause() |
W iOS stan Active jest obsługiwany przez UIApplicationDelegate. Główna metoda to applicationDidBecomeActive(_:). Jest wywoływana przy pierwszym uruchomieniu aplikacji oraz przy powrocie z Inactive. Ta metoda to idealne miejsce do wznowienia zadań, które zostały wstrzymane przy przejściu do Inactive: uruchamianie animacji, wznawianie timerów, restart czujników, sprawdzanie aktualizacji danych na serwerze.
Od iOS 13 Apple wprowadziło UISceneDelegate do obsługi wielu okien na iPadzie. W tym przypadku applicationDidBecomeActive zostaje zastąpione przez sceneDidBecomeActive dla każdej sceny. Aplikacje obsługujące tylko jeden ekran mogą nadal używać UIApplicationDelegate. Oba podejścia są wywoływane w momencie, gdy aplikacja lub scena staje się aktywna.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// Aplikacja stała się aktywna — wznawiamy zadania
func applicationDidBecomeActive(_ application: UIApplication) {
resumeAnimations()
restartTimers()
refreshDataIfNeeded()
startObservingSensors()
}
// Aplikacja traci aktywność — wstrzymujemy
func applicationWillResignActive(_ application: UIApplication) {
pauseAnimations()
stopTimers()
saveDraftData()
}
private func resumeAnimations() {
UIView.animate(withDuration: 0.3) {
// Wznawianie animacji UI
}
}
private func refreshDataIfNeeded() {
let lastRefresh = UserDefaults.standard.object(forKey: "lastRefresh") as? Date ?? .distantPast
if Date().timeIntervalSince(lastRefresh) > 300 {
fetchDataFromServer()
}
}
}Kod pokazuje poprawną obsługę Active w UIKit. applicationDidBecomeActive wznawia animacje, timery i sprawdza, czy wymagana jest aktualizacja danych. applicationWillResignActive wstrzymuje wszystko, co może zużywać zasoby, i zapisuje wersje robocze. Taka para metod gwarantuje, że aplikacja prawidłowo reaguje na zmianę stanu.
W SwiftUI nie ma AppDelegate — zarządzanie stanem odbywa się przez Environment<ScenePhase>. Wartość .active jest ustawiana, gdy scena znajduje się na pierwszym planie i jest interaktywna. SwiftUI automatycznie restartuje animacje i aktualizacje przy powrocie do Active. Deweloper musi tylko subskrybować onChange, aby wykonywać efekty uboczne.
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 stała się aktywna")
resumeWork()
case .inactive:
print("Scena stała się nieaktywna")
pauseWork()
case .background:
print("Scena przeszła w tło")
saveState()
@unknown default:
break
}
}
}
private func resumeWork() {
// Wznawianie zapytań sieciowych, animacji
}
private func pauseWork() {
// Wstrzymanie zadań wrażliwych na czas
}
private func saveState() {
// Zapis stanu aplikacji
}
}W SwiftUI scenePhase to jedyne źródło prawdy o stanie aplikacji. onChange pozwala wykonywać akcje przy każdej zmianie. Należy pamiętać, że scenePhase jest dostępna tylko od iOS 14+ i w SwiftUI Lifecycle. Dla aplikacji UIKit z ekranami SwiftUI używaj podejścia z UIApplicationDelegate.
Active można osiągnąć na kilka sposobów. Pierwszy i oczywisty — zimny start: użytkownik naciska ikonę, aplikacja przechodzi z Not Running przez Inactive do Active. Drugi — powrót z tła: użytkownik przełącza się z powrotem do aplikacji przez App Switcher, aplikacja przechodzi przez Inactive i staje się Active. Trzeci — powrót z tymczasowego przerwania: użytkownik kończy rozmowę, zamyka Control Center lub odpowiada na powiadomienie — aplikacja wraca z Inactive do Active.
Not Running → Inactive → Active — zimny start. Background → Inactive → Active — powrót z tła. Inactive → Active — powrót z tymczasowego przerwania. W każdym przypadku wywoływane jest applicationDidBecomeActive, ale kontekst może się różnić. Przy zimnym starcie przed Active wywoływane jest didFinishLaunchingWithOptions, przy powrocie z tła — willEnterForeground. Deweloper może wykorzystać te różnice do wyboru strategii przywracania stanu.
| Scenariusz | Ścieżka przejścia | Callbacki iOS | Callbacki Android |
|---|---|---|---|
| Zimny start | Not Running → Active | didFinishLaunching → didBecomeActive | onCreate → onStart → onResume |
| Powrót z tła | Background → Active | willEnterForeground → didBecomeActive | onRestart → onStart → onResume |
| Powrót z Suspended | Suspended → Active | willEnterForeground → didBecomeActive | onRestart → onStart → onResume |
| Po przerwaniu | Inactive → Active | didBecomeActive | onResume |
Ważna uwaga: przy powrocie z Suspended iOS nie wywołuje didFinishLaunchingWithOptions, ponieważ aplikacja była już załadowana do pamięci. Oznacza to, że kod inicjalizacyjny umieszczony w tej metodzie nie jest wykonywany ponownie. Deweloperzy często o tym zapominają i przenoszą krytyczną logikę do applicationWillEnterForeground lub applicationDidBecomeActive dla obu scenariuszy.
W Androidzie odpowiednikiem Active jest stan Activity po wywołaniu onResume(). Activity jest uważane za aktywne, gdy znajduje się na pierwszym planie i przyjmuje dane wejściowe użytkownika. Ten stan odpowiada wierzchołkowi stosu Activity. Jeśli inne Activity pojawi się na wierzchu (nawet częściowo), bieżące Activity przechodzi w stan onPause — odpowiednik iOS Inactive.
Kluczowa różnica w Androidzie — wiele Activity może być aktywnych jednocześnie w trybie multi-window (split screen, freeform). W tym przypadku Activity, z którym użytkownik wchodzi w interakcję, jest uważane za aktywne, a sąsiednie — za wstrzymane (onPause). iOS nie obsługuje multi-window na iPhonie, tylko na iPadzie przez UIScene.
class MainActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
// Aplikacja stała się aktywna — wznawiamy zadania
resumeCameraPreview()
startLocationUpdates()
activateSensors()
}
override fun onPause() {
super.onPause()
// Aplikacja traci aktywność — zwalniamy zasoby
releaseCamera()
stopLocationUpdates()
deactivateSensors()
}
private fun resumeCameraPreview() {
// Uruchomienie podglądu kamery (wymaga uprawnień)
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()
)
}
}Kod pokazuje obsługę Active w Androidzie przez onResume/onPause. onResume wznawia pracę z kamerą, geolokalizacją i czujnikami — zasobami, które powinny być aktywne tylko gdy aplikacja jest widoczna dla użytkownika. onPause zwalnia te zasoby, aby nie zużywać baterii. CameraX lifecycle-aware API automatycznie wstrzymuje podgląd przy onPause.
Pierwsza zasada — nie wykonuj ciężkich operacji w applicationDidBecomeActive lub onResume. Ładowanie danych, parsowanie JSON, praca z bazą danych — wszystko to powinno być asynchroniczne i nie blokować głównego wątku. Używaj GCD (DispatchQueue) w iOS i Coroutines w Kotlinie do zadań tła. Główny wątek powinien tylko aktualizować UI i uruchamiać operacje asynchroniczne.
Druga zasada — synchronizuj stan przy każdym powrocie do Active. Użytkownik mógł zmienić ustawienia w aplikacji systemowej, otrzymać push-powiadomienie lub zaktualizować dane w innej aplikacji. Sprawdzaj aktualność cache przy przejściu do Active — być może dane są nieaktualne od czasu nieobecności użytkownika.
Trzecia zasada — nie polegaj na Active jako jedynym stanie. Aplikacja może pominąć Active i przejść bezpośrednio z Not Running do Background (jeśli została uruchomiona w tle). W iOS dzieje się to przy uruchomieniu przez push-powiadomienie z opcją content-available. W Androidzie — przy uruchomieniu przez BroadcastReceiver. Zawsze sprawdzaj bieżący stan przed wykonaniem operacji UI.
Czwarta zasada — używaj Activity Result API w Androidzie zamiast onActivityResult. Pozwala to obsługiwać wyniki wywołania kamery, galerii lub uprawnień bezpośrednio w stanie Active bez utraty danych przy odtworzeniu Activity. Dla iOS używaj async/await z UIApplication.shared.open dla okien systemowych.
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 {
// Odłożyć wykonanie do powrotu do Active
NotificationCenter.default.addObserver(
forName: .appDidBecomeActive,
object: nil,
queue: .main
) { _ in
block()
}
}
}
}
extension Notification.Name {
static let appDidBecomeActive = Notification.Name("appDidBecomeActive")
}Kod pokazuje menedżera stanu Active, który pozwala innym komponentom aplikacji sprawdzać bieżący stan aktywny. performWhenActive albo wykonuje blok natychmiast, jeśli aplikacja jest aktywna, albo odkłada wykonanie do powrotu do Active. Jest to przydatne dla serwisów, które muszą wykonać działanie po tym, jak użytkownik wróci do aplikacji.
Często zadawane pytania
Metoda jest wywoływana za każdym razem, gdy aplikacja przechodzi do stanu aktywnego: przy pierwszym uruchomieniu, przy powrocie z tła, po zamknięciu Control Center lub Notification Center, po zakończeniu rozmowy. W normalnej sesji może być wywołana 5–10 razy w zależności od działań użytkownika. Nie umieszczaj w tej metodzie inicjalizacji jednorazowej.
Visible — nieoficjalny termin oznaczający, że aplikacja jest widoczna na ekranie, ale może nie przyjmować zdarzeń (na przykład częściowo zasłonięta przez inne okno na iPadzie). Active — oficjalny stan, w którym aplikacja jest zarówno widoczna, jak i interaktywna. Na iPhonie aplikacja Visible jest zawsze Active, na iPadzie możliwa jest sytuacja Visible + Inactive.
willEnterForeground jest wywoływane przy powrocie z tła, ale aplikacja nie jest jeszcze aktywna — znajduje się w Inactive. didBecomeActive jest wywoływane po tym, jak aplikacja stała się w pełni interaktywna. Jeśli chcesz wykonać działanie zanim użytkownik zobaczy interfejs — użyj willEnterForeground. Jeśli po wyświetleniu — didBecomeActive.
Nie. Active zakłada, że aplikacja znajduje się na pierwszym planie i jest wyświetlana na ekranie. Bez widocznego UI aplikacja może być w Background lub Suspended. Wyjątek — iPad multi-window, gdzie jedno okno może być aktywne, a drugie nie, ale oba są widoczne. VoiceOver i dyktafon nie zmieniają tej zasady.
Na symulatorze iOS naciśnij Cmd+Shift+H, aby przejść do ekranu głównego (aplikacja przechodzi do Background), następnie ponownie kliknij ikonę aplikacji. Użyj Cmd+L do zablokowania ekranu (willResignActive) i odblokowania (didBecomeActive). Do testowania Inactive wywołaj Control Center (Cmd+Shift+; dla klawiatury macOS) lub Notification Center.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również