Activity Lifecycle to zestaw metod wywołania zwrotnego, które Android wywołuje przy przejściu Activity między stanami: tworzenie, widoczność, fokus wejścia, częściowa utrata widoczności, całkowite ukrycie i zniszczenie. System zarządza cyklem życia każdego ekranu aplikacji, począwszy od wywołania onCreate() aż do onDestroy(). Zrozumienie tych stanów jest obowiązkowym wymogiem stabilnej aplikacji Android, ponieważ nieprawidłowe obsłużenie przejść między metodami prowadzi do wycieków pamięci, utraty danych użytkownika i nieoczekiwanych crashy. Więcej o architekturze Androida przeczytasz w ogólnym artykule o Androidzie.
Najważniejsze
Activity Lifecycle (cykl życia Activity) to automat stanów, przez który przechodzi każdy ekran aplikacji Android od momentu utworzenia do całkowitego zniszczenia. System Android zarządza tym procesem na podstawie działań użytkownika: otwarcie aplikacji, zminimalizowanie, obrót ekranu, odpowiedź na połączenie przychodzące, przełączanie między aplikacjami i zakończenie pracy.
Zrozumienie cyklu życia jest niezbędne dla każdego dewelopera Android, ponieważ system może w każdej chwili zniszczyć Activity przy braku pamięci — a aplikacja musi poprawnie przywrócić swój stan. Według danych Google Android Vitals (2025), aplikacje, które nie obsługują zapisu stanu w onSaveInstanceState(), wykazują o 42% więcej crashy przy odtwarzaniu Activity.
Cykl życia obejmuje sześć głównych metod wywołania zwrotnego: onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy(). Dodatkowo istnieje metoda onRestart(), która jest wywoływana przed onStart(), gdy Activity powraca ze stanu zatrzymanego. Każda metoda ma ściśle określone przeznaczenie i czas wykonania — system wywołuje je sekwencyjnie, a deweloper może nadpisać dowolną z nich, aby wykonać własną logikę.
Cykl można podzielić na trzy kluczowe etapy: cały czas życia (onCreate → onDestroy), widoczny czas życia (onStart → onStop) i czas życia na pierwszym planie (onResume → onPause). Zrozumienie tych trzech poziomów pomaga prawidłowo rozłożyć kod inicjalizacji i zwalniania zasobów.
Każda metoda cyklu życia wykonuje ściśle określone zadanie. System wywołuje je w ustalonej kolejności, a deweloper powinien nadpisywać tylko te metody, które są potrzebne dla konkretnej logiki. Nie zaleca się bezpośredniego wywoływania metod cyklu życia — zajmuje się tym Android Runtime.
Typowa sekwencja przy uruchamianiu aplikacji: onCreate → onStart → onResume. Po naciśnięciu przycisku „Wstecz“: onPause → onStop → onDestroy. Przy minimalizacji: onPause → onStop, następnie przy powrocie: onRestart → onStart → onResume.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onStart() {
super.onStart()
}
override fun onResume() {
super.onResume()
}
override fun onPause() {
super.onPause()
}
override fun onStop() {
super.onStop()
}
override fun onDestroy() {
super.onDestroy()
}
override fun onRestart() {
super.onRestart()
}
}
Każda nadpisana metoda musi wywoływać super-wersję — bez tego system nie będzie mógł poprawnie zakończyć przejścia między stanami. Ta zasada jest zapisana w dokumentacji Android Developers i sprawdzana przez reguły lint Android Studio.
Pierwszy poziom — cały czas życia (entire lifetime): okres między onCreate a onDestroy. Tutaj wykonuje się jednorazowa inicjalizacja i końcowe zwalnianie globalnych zasobów. Drugi poziom — widoczny czas życia (visible lifetime): między onStart a onStop. Activity jest widoczne na ekranie, ale może być częściowo zasłonięte przez inne okno. Trzeci poziom — czas życia na pierwszym planie (foreground lifetime): między onResume a onPause. Activity znajduje się na szczycie stosu zadań i współdziała z użytkownikiem.
onCreate() — pierwsza i jedyna obowiązkowa metoda cyklu życia Activity. Jest wywoływana przez system raz przy tworzeniu instancji Activity. Ta metoda przyjmuje parametr savedInstanceState: Bundle?, który zawiera wcześniej zapisany stan, jeśli Activity jest odtwarzane po zniszczeniu — na przykład przy obrocie ekranu.
Wewnątrz onCreate wykonywane są następujące zadania: inicjalizacja interfejsu użytkownika przez setContentView() z przekazaniem zasobu layoutu, powiązanie elementów View przez findViewById(), konfiguracja adapterów dla RecyclerView i ViewPager, przywracanie stanu z savedInstanceState, inicjalizacja ViewModel i LiveData, konfiguracja nasłuchiwaczy kliknięć i gestów. Metoda powinna zakończyć się jak najszybciej — długotrwałe operacje blokują renderowanie pierwszej klatki, co wydłuża czas uruchamiania aplikacji.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_profile)
val userNameText: TextView = findViewById(R.id.user_name)
val loadButton: Button = findViewById(R.id.load_button)
if (savedInstanceState != null) {
userNameText.text = savedInstanceState.getString("user_name")
}
loadButton.setOnClickListener {
loadUserProfile()
}
}
Jeśli Activity jest tworzone po raz pierwszy, savedInstanceState jest równe null. Przy odtwarzaniu po obrocie ekranu Bundle zawiera dane zapisane w onSaveInstanceState(). Sprawdzenie na null — standardowa praktyka poprawnego przywracania UI bez utraty danych wprowadzonych przez użytkownika.
onStart() jest wywoływane zaraz po onCreate() lub po onRestart(), gdy Activity staje się widoczne dla użytkownika. W tym stanie Activity nie znajduje się jeszcze na pierwszym planie i nie może współdziałać z użytkownikiem, ale jego interfejs użytkownika jest już widoczny na ekranie. Na przykład przy uruchamianiu aplikacji między wywołaniem onStart a onResume system renderuje pierwszą klatkę interfejsu.
W metodzie onStart zwykle wykonuje się następujące czynności: uruchamianie animacji, które powinny działać, gdy Activity jest widoczne; rejestracja odbiorników transmisji (BroadcastReceiver); podłączanie do usług geolokalizacji i czujników; aktualizacja danych z ViewModel lub Room. Tutaj również wykonuje się wiązanie z Bound-serwisami przez bindService(), jeśli aplikacja używa architektury klient-serwer wewnątrz procesu.
override fun onStart() {
super.onStart()
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
5000L,
10f,
locationListener
)
}
override fun onStop() {
super.onStop()
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.removeUpdates(locationListener)
}
Ważna zasada: zasoby podłączone w onStart muszą być zwalniane w onStop. Gwarantuje to, że gdy Activity nie jest widoczne na ekranie, nie zużywa baterii i zasobów systemowych. Google Play Store sprawdza aplikacje pod kątem wycieków LocationListener i innych usług systemowych przy moderacji aktualizacji.
onResume() — stan, w którym Activity znajduje się na pierwszym planie i jest gotowe do interakcji z użytkownikiem. To jest roboczy stan ekranu: system przekazuje Activity fokus wejścia, a wszystkie zdarzenia dotyku, wprowadzania z klawiatury i gestów są kierowane do tego ekranu. Metoda onResume jest wywoływana za każdym razem, gdy Activity wraca na pierwszy plan — po zakończeniu innego Activity, po zamknięciu okna dialogowego, po odblokowaniu urządzenia.
W onResume wykonuje się: wznowienie animacji, które zostały wstrzymane w onPause; otwarcie kamery i innych ekskluzywnych zasobów; rejestrację nasłuchiwaczy czujników (akcelerometr, żyroskop); uruchomienie timerów i stopera dla UI; aktualizację zawartości ekranu aktualnymi danymi. W parze onResume / onPause pracuje się z zasobami, które powinny być aktywne tylko przy fokusie — na przykład ciągłe rozpoznawanie mowy lub przechwytywanie wideo.
override fun onResume() {
super.onResume()
cameraHolder.openCamera()
animator.resume()
sensorManager.registerListener(
stepCounter,
sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER),
SensorManager.SENSOR_DELAY_NORMAL
)
}
override fun onPause() {
super.onPause()
cameraHolder.closeCamera()
animator.pause()
sensorManager.unregisterListener(stepCounter)
}
Różnica między onStart a onResume jest istotna: Activity może być widoczne (onStart), ale nie aktywne (onResume) — na przykład gdy nad nim wyświetla się okno dialogowe lub przezroczysty ekran blokady. Właśnie w onResume, a nie w onStart, należy otwierać ekskluzywne zasoby, do których potrzebny jest monopolistyczny dostęp.
onPause() jest wywoływane, gdy Activity traci fokus wejścia, ale pozostaje częściowo widoczne. Typowe scenariusze: otwarcie okna dialogowego, naciśnięcie przycisku „Ostatnie aplikacje“, połączenie przychodzące, naciśnięcie przycisku „Dom“ (w tym przypadku po onPause nastąpi onStop). Metoda onPause — ostatnie niezawodne miejsce do zapisu danych, których użytkownik nie powinien stracić.
W onPause wykonuje się: zapis szkiców wiadomości i formularzy w Room lub SharedPreferences; zatrzymanie animacji i odtwarzania wideo; zamknięcie kamery i zwolnienie monopolistycznych zasobów; anulowanie kosztownych operacji, niekrytycznych dla tła. Metoda onPause powinna zakończyć się w mniej niż 100 milisekund — system blokuje przejście do następnego Activity, dopóki onPause nie zwróci sterowania, a przekroczenie limitu prowadzi do ANR (Application Not Responding).
override fun onPause() {
super.onPause()
val editor = SharedPreferences.Manager ...
editor.putString("draft_text", draftEditText.text.toString())
editor.apply()
videoView.pause()
cameraHolder.release()
}
Ważne: onPause wykonuje się w wątku UI, dlatego wszelkie blokujące operacje, takie jak zapis do bazy danych przez Room z synchronicznym zapytaniem, należy zastąpić asynchronicznymi (korutyny) lub wykonywać w wątku tła. Używaj apply() zamiast commit() dla SharedPreferences — apply zapisuje dane asynchronicznie i nie blokuje wątku UI.
onStop() jest wywoływane, gdy Activity przestaje być widoczne dla użytkownika. Dzieje się to w następujących przypadkach: Activity jest całkowicie zasłonięte przez inne Activity; użytkownik nacisnął przycisk „Dom“ lub przełączył się na inną aplikację; Activity kończy działanie (następnie zostanie wywołane onDestroy). W stanie onStop Activity pozostaje w pamięci i zachowuje wszystkie swoje pola — nie jest zniszczone, ale też nie jest aktywne.
W onStop wykonuje się: wypisanie z BroadcastReceiver zarejestrowanych w onStart; odłączenie od Bound-serwisów; zwolnienie LocationListener, SensorListener i innych nasłuchiwaczy systemowych; zatrzymanie długotrwałych operacji w tle, które nie są potrzebne, gdy aplikacja jest ukryta; zapis bieżącego stanu UI w Bundle przez onSaveInstanceState(), jeśli nie zostało to zrobione w onPause.
override fun onStop() {
super.onStop()
unregisterReceiver(connectivityReceiver)
unbindService(serviceConnection)
if (isChangingConfigurations()) {
Log.d("Lifecycle", "Activity odtwarzane z powodu konfiguracji")
}
}
System może zniszczyć Activity w stanie onStop bez wywołania onDestroy przy braku pamięci. Dlatego wszystkie krytyczne dane muszą być zapisane przed przejściem do onStop. Flaga isChangingConfigurations() pozwala określić, czy wywołanie onStop jest związane z obrotem ekranu — w tym przypadku Activity zostanie odtworzone, a nie zakończone.
onDestroy() — ostatnia metoda cyklu życia, wywoływana przed całkowitym zniszczeniem Activity. System wywołuje onDestroy w dwóch przypadkach: Activity kończy działanie przez wywołanie finish() lub użytkownik naciska przycisk „Wstecz“; Activity jest niszczone przez system z powodu zmiany konfiguracji (na przykład obrót ekranu) i zostanie utworzone od nowa. Metoda onDestroy pozwala na wykonanie końcowego czyszczenia zasobów: odwiązanie wątków i korutyn, zamknięcie trwale otwartych kursorów i socketów, zwolnienie pamięci natywnej przez NDK.
override fun onDestroy() {
super.onDestroy()
backgroundJob.cancel()
dbHelper.close()
if (isFinishing) {
Log.d("Lifecycle", "Activity kończy się ostatecznie")
} else {
Log.d("Lifecycle", "Activity zostanie odtworzone")
}
}
Ważna uwaga: wywołanie onDestroy nie jest gwarantowane, jeśli proces aplikacji został zabity przez system (out-of-memory kill). Dlatego poleganie na onDestroy przy zapisie danych jest niedozwolone — to zadanie rozwiązuje się w onPause lub onStop. Właściwość isFinishing pozwala odróżnić zakończenie Activity przez finish() od odtworzenia przy zmianie konfiguracji.
onRestart() jest wywoływane przed onStart(), gdy Activity powraca ze stanu zatrzymanego (onStop) z powrotem na pierwszy plan. Dzieje się tak, gdy użytkownik ponownie otwiera aplikację z menu „Ostatnie“ lub wraca do Activity, naciskając „Wstecz“ w ekranie potomnym. Metoda onRestart pozwala na wykonanie logiki różnej od onCreate — na przykład aktualizację danych, które mogły się zmienić, gdy Activity było ukryte.
override fun onRestart() {
super.onRestart()
refreshDataFromNetwork()
Log.d("Lifecycle", "Activity uruchamiane ponownie ze stosu")
}
Typowy scenariusz: użytkownik otworzył aplikację, przełączył się na inne zadanie, a po godzinie wrócił. W onRestart aplikacja może sprawdzić aktualność danych i, jeśli minęło dużo czasu, zaproponować przeładowanie treści. Poprawia to doświadczenie użytkownika i zmniejsza prawdopodobieństwo pokazania nieaktualnych informacji.
Obrót ekranu — najczęstszy scenariusz odtwarzania Activity. Domyślnie Android niszczy bieżące Activity i tworzy nowe przy każdej zmianie orientacji. Jeśli stan nie zostanie zapisany, użytkownik straci wszystkie wprowadzone dane. W tym celu Android udostępnia dwa mechanizmy: onSaveInstanceState() dla danych serializowalnych i ViewModel dla danych, które przetrwają zmiany konfiguracji.
onSaveInstanceState() jest wywoływane przed zniszczeniem Activity w celu zapisania tymczasowego stanu. Zapisane dane są przekazywane do onCreate przez parametr savedInstanceState i do metody onRestoreInstanceState(), która jest wywoływana po onStart. Bundle ma ograniczenie rozmiaru — około 500 KB, dlatego duże ilości danych (na przykład bitmapy) zapisuje się przez ViewModel.
<!-- AndroidManifest.xml — utrwalenie orientacji -->
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize" />
Utrwalenie orientacji przez android:configChanges zapobiega odtwarzaniu Activity, ale jest uważane za antywzorzec, jeśli aplikacja powinna obsługiwać obie orientacje. Współczesne zalecenie Google — używanie ViewModel w połączeniu z onSaveInstanceState dla danych, które użytkownik wprowadza w UI.
Fragment ma własny cykl życia, podobny do Activity, ale z dodatkowymi metodami: onAttach, onCreate, onCreateView, onViewCreated, onStart, onResume, onPause, onStop, onDestroyView, onDestroy, onDetach. Fragment zawsze istnieje wewnątrz Activity, a jego cykl życia jest związany z cyklem życia Activity-kontenera. Jeśli Activity jest niszczone, Fragment podąża za nim.
Główna różnica: Fragment zarządza nie tylko stanem komponentu, ale także hierarchią View. Metoda onCreateView zwraca główny View fragmentu, a onDestroyView — niszczy tę hierarchię. Pozwala to Fragmentowi przetrwać odtworzenie Activity przy obrocie ekranu: Fragment jest zachowany, a jego View tworzone od nowa w onCreateView.
class ProfileFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_profile, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val avatarImage: ImageView = view.findViewById(R.id.avatar_image)
loadAvatar(avatarImage)
}
}
Zrozumienie różnicy między onCreate a onCreateView jest krytyczne: onCreate jest wywoływane raz na życie Fragmentu (nawet przy odtwarzaniu View), a onCreateView — za każdym razem, gdy Fragment tworzy lub odtwarza swoją hierarchię View. Inicjalizację danych wykonuje się w onCreate, a wiązanie UI — w onViewCreated.
LifecycleObserver — komponent biblioteki Android Jetpack, który pozwala reagować na zmiany cyklu życia bez nadpisywania metod w Activity lub Fragment. Zamiast powielać kod w każdej metodzie cyklu życia, deweloper tworzy osobną klasę z adnotacjami @OnLifecycleEvent i przekazuje ją do lifecycle.addObserver().
Jetpack udostępnia również klasę LifecycleOwner — interfejs, który implementują AppCompatActivity i Fragment. Każdy obiekt implementujący LifecycleOwner może zarządzać subskrypcjami LiveData, korutyn przez lifecycleScope i pracą WorkManager w powiązaniu z cyklem życia. To kamień węgielny nowoczesnej architektury Android opartej na MVVM i Jetpack.
class MyLocationObserver(private val context: Context) : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
startLocationUpdates()
}
override fun onStop(owner: LifecycleOwner) {
stopLocationUpdates()
}
}
// W Activity:
lifecycle.addObserver(MyLocationObserver(this))
Używanie DefaultLifecycleObserver upraszcza testowanie, zmniejsza powielanie kodu i czyni logikę cyklu życia wielokrotnego użytku między różnymi ekranami. To nowoczesny zamiennik ręcznego nadpisywania onStart/onStop w każdym Activity. W aplikacjach Android opracowanych przez IT Sectr stosujemy LifecycleObserver do geolokalizacji, skanowania Bluetooth i analityki — skraca to ilość kodu boilerplate o 30–40%.
Często zadawane pytania
Jeśli nie wywołasz super.onCreate() lub jakiejkolwiek innej super-metody cyklu życia, system wyrzuci wyjątek SuperNotCalledException i aplikacja ulegnie crashowi. To sztywny wymóg Android Runtime — każda metoda musi delegować wykonanie do klasy bazowej, w przeciwnym razie wewnętrzny automat stanów nie będzie mógł przejść do następnego stanu.
Activity jest odtwarzane przy obrocie ekranu, ponieważ zmiana orientacji to zmiana konfiguracji urządzenia (configuration change). Domyślnie Android niszczy Activity i tworzy nowe, aby załadować alternatywne zasoby (layout-land, values-land). Aby wyłączyć odtwarzanie, można dodać atrybut android:configChanges w manifeście, ale Google zaleca używanie ViewModel do zapisu danych.
Krytyczne dane zapisuje się w onPause(), ponieważ to ostatnia metoda, która jest gwarantowanie wywoływana przed tym, jak aplikacja może zostać zabita przez system. Po onStop i onDestroy system może zakończyć proces bez wywoływania dodatkowych metod. Dla szkiców i danych tymczasowych używaj SharedPreferences z apply() lub Room z korutynami.
onPause jest wywoływane, gdy Activity traci fokus, ale pozostaje częściowo widoczne (na przykład otwarte okno dialogowe). onStop jest wywoływane, gdy Activity jest całkowicie ukryte z ekranu przez inne Activity lub naciśnięcie przycisku „Dom“. Główna praktyczna różnica: onPause — ostatni punkt zapisu danych, onStop — miejsce zwalniania nasłuchiwaczy i usług systemowych, które nie są potrzebne w tle.
ViewModel — komponent Android Jetpack, który przechowuje dane UI i automatycznie przetrwa zmiany konfiguracji (obrót ekranu). ViewModel nie jest niszczony przy odtwarzaniu Activity: żyje, dopóki LifecycleOwner (Activity lub Fragment) nie zakończy się ostatecznie. Rozwiązuje to problem zapisu danych przy obrocie ekranu bez używania Bundle i onSaveInstanceState. ViewModel — obowiązkowy element architektury MVVM rekomendowanej przez Google.
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ż