onStop — metoda cyklu życia Activity w Androidzie, wywoływana przez system, gdy Activity przestaje być widoczne dla użytkownika. Activity przechodzi w stan Stopped po tym, jak nowe Activity całkowicie je zasłoni, albo po zminimalizowaniu aplikacji. W metodzie onStop programista jest zobowiązany zatrzymać animacje, zwolnić zasoby kamery i czujników, zapisać wersje robocze wprowadzonych danych. Według Android Vitals (Google, 2025), poprawne obsłużenie onStop zmniejsza liczbę ANR (Application Not Responding) przy minimalizowaniu aplikacji o 35%. Po onStop system może wywołać onRestart (powrót na ekran) lub onDestroy (całkowite zakończenie). Dokumentacja Android Developers na temat cyklu życia Activity opisuje onStop jako granicę między stanem widocznym a niewidocznym.
Najważniejsze
onStop — to callback metody klasy AppCompatActivity (i jej poprzednika Activity), który jest wywoływany przez system operacyjny Android, gdy Activity przestaje być całkowicie widoczne dla użytkownika. W tym momencie Activity jest zasłonięte przez inne Activity, okno dialogowe, program uruchamiający systemu lub ekran blokady. Z punktu widzenia cyklu życia, onStop następuje po onPause i sygnalizuje, że Activity nie jest już widoczne na ekranie, chociaż sam obiekt Activity i jego stan pozostają w pamięci.
Gdy Activity przechodzi w stan Stopped (zatrzymane), zachowuje swój stan w pamięci RAM — wszystkie pola, hierarchia widoków i ViewModel pozostają dostępne. To odróżnia Stopped od stanu zniszczonego (Destroyed), w którym Activity jest całkowicie usuwane. System UI może zabić proces aplikacji znajdującej się w stanie Stopped przy braku pamięci — jest to tak zwany process death. Programista jest zobowiązany zapisać krytyczne dane (wersje robocze, pozycję przewijania) w onSaveInstanceState(), które jest wywoływane przed onStop, aby zagwarantować przywrócenie przy zabiciu procesu.
Według specyfikacji Android Compatibility Definition Document (CDD) dla wersji 14+, proces w stanie Stopped ma obniżony priorytet przy zabijaniu przez OOM Killer — niższy niż procesy w fazie Background, ale wyższy niż procesy w pamięci podręcznej. Według statystyk Google, 68% przypadków zabijania procesów ma miejsce, gdy Activity znajduje się w stanie Stopped, a nie Paused.
onStop jest wywoływane przy całkowitej utracie widoczności Activity, niezależnie od przyczyny: uruchomienie nowego Activity nad bieżącym, zminimalizowanie aplikacji (naciśnięcie Home), blokada ekranu, przychodzące połączenie lub otwarcie okna systemowego. We wszystkich tych przypadkach Activity najpierw otrzymuje onPause (częściowa utrata fokusu), a następnie onStop (całkowita utrata widoczności).
Główne scenariusze wywołania onStop:
Ważne jest, aby zrozumieć, że onStop nie jest wywoływane przy obrocie ekranu — w tym przypadku Activity jest niszczone (onPause → onStop → onDestroy) i tworzone od nowa (onCreate → onStart → onResume). Wyjątkiem jest flaga android:configChanges="orientation" w manifeście, przy której Activity nie jest odtwarzane, a otrzymuje wywołanie onConfigurationChanged().
onStop zajmuje centralne miejsce w sekwencji cyklu życia Activity między stanem widocznym a niewidocznym. Pełna sekwencja: onCreate → onStart → onResume → (stan aktywny) → onPause → onStop → onDestroy (lub onRestart → onStart → onResume przy powrocie).
| Stan | Metoda | Widoczność | Interakcja | Pamięć |
|---|---|---|---|---|
| Created | onCreate | Nie | Nie | Alokowana |
| Started | onStart | Cięściowo | Nie | Pełna |
| Resumed | onResume | Pełna | Tak | Pełna |
| Paused | onPause | Cięściowo | Nie | Pełna |
| Stopped | onStop | Nie | Nie | Pełna* |
| Destroyed | onDestroy | Nie | Nie | Zwolniona |
*W stanie Stopped Activity jest przechowywane w pamięci, ale może zostać zabite przez system przy braku zasobów. Priorytet zabijania procesów Stopped — przedostatni, wyższy tylko niż puste procesy w pamięci podręcznej.
onStop i onSaveInstanceState: System wywołuje onSaveInstanceState(Bundle) przed onStop, aby zapisać dynamiczny stan UI. Programista nadpisuje tę metodę, aby zapisać w Bundle wartości pól wejściowych, pozycję RecyclerView, wybrane elementy. Nawet jeśli Activity nie zostanie zniszczone (użytkownik po prostu zminimalizował i wrócił), Bundle jest przekazywany do onCreate przy zmianach konfiguracyjnych. Google zaleca zapisywanie tylko przejściowego stanu UI — nie danych repozytorium ani ViewModel, które żyją poza Activity.
W onStop programista jest zobowiązany zwolnić wszystkie zasoby, które nie są potrzebne, gdy Activity nie jest widoczne. Zmniejsza to obciążenie baterii, procesora i pamięci, a także zapobiega ANR przy powrocie do aktywności.
Co zwalniać w onStop:
Czego nie robić w onStop: Nie wykonuj długotrwałych operacji — zapisywanie dużych danych w BD, żądania sieciowe, złożone obliczenia. onStop wykonuje się na głównym wątku i blokuje powrót do Activity. Do długotrwałych operacji używaj WorkManager z opóźnieniem lub korutyn w viewModelScope. Nie zwalniaj zasobów ViewModel — ViewModel przetrwa onStop i zostanie użyty przy powrocie.
onPause i onStop różnią się stopniem utraty widoczności i zakresem obowiązkowych działań. onPause jest wywoływane przy częściowej utracie fokusu (na przykład otwarcie okna dialogowego lub menu systemowego), onStop — przy całkowitej utracie widoczności. Ta różnica jest ważna przy wyborze, które zasoby zwalniać na każdym etapie.
| Charakterystyka | onPause | onStop |
|---|---|---|
| Stopień widoczności | Cięściowo widoczne | Całkowicie niewidoczne |
| Fokus | Utracony | Utracony |
| Czas wykonania | Do 500 ms | Do 5 s (ANR-timeout) |
| Zasoby do zwolnienia | Krytyczne (media, aparat) | Wszystkie niewidoczne (czujniki, animacje, location) |
| Przywrócenie | onResume | onRestart → onStart → onResume |
| Priorytet procesu | Wysoki (Foreground) | Średni (Background) |
Ogólna zasada: w onPause zwalniaj zasoby systemowe, które natychmiast wpływają na doświadczenie użytkownika innej aplikacji (aparat, odtwarzacz multimedialny), w onStop — wszystkie pozostałe zasoby, niepotrzebne przy ukrytym Activity. Google zaleca w onPause zapisywać krytyczne dane użytkownika (wersja robocza e-maila, ustawienia), ponieważ onStop może nie wystąpić przy szybkim przełączaniu.
Gdy użytkownik wraca do ukrytego Activity, system wywołuje onRestart → onStart → onResume. Metoda onRestart sygnalizuje, że Activity wraca ze stanu Stopped. To ważny etap do przywrócenia UI i zasobów, które zostały zwolnione w onStop.
Sekwencja wywołań przy powrocie:
Jeśli proces aplikacji został zabity przez system w stanie Stopped, onCreate jest wywoływane zamiast onRestart, a Bundle z onSaveInstanceState jest przekazywany do przywrócenia stanu. Ten scenariusz (process death) — jeden z najczęstszych powodów błędów w aplikacjach Android: programiści implementują onRestart, ale zapominają uwzględnić przywrócenie przez onCreate po zabiciu procesu.
Pokazuje poprawne wypisanie się z czujników i zatrzymanie animacji przy ukrywaniu Activity. Po powrocie na ekran zasoby są przywracane w onStart.
class MainActivity : AppCompatActivity() {
private lateinit var sensorManager: SensorManager
private var accelerometer: Sensor? = null
private var rotationAnimator: ObjectAnimator? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
}
override fun onStart() {
super.onStart()
accelerometer?.let {
sensorManager.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_NORMAL)
}
rotationAnimator = ObjectAnimator.ofFloat(findViewById(R.id.icon), "rotation", 0f, 360f)
rotationAnimator?.apply {
duration = 3000
repeatMode = ValueAnimator.RESTART
repeatCount = ValueAnimator.INFINITE
start()
}
}
override fun onStop() {
super.onStop()
sensorManager.unregisterListener(sensorListener)
rotationAnimator?.cancel()
}
override fun onRestart() {
super.onRestart()
Log.d("MainActivity", "Activity powraca ze stanu Stopped")
}
private val sensorListener = SensorEventListener { event, _ ->
Log.d("MainActivity", "Accel: x=${event.values[0]}, y=${event.values[1]}, z=${event.values[2]}")
}
}
Kod rejestruje czujnik akcelerometru i uruchamia nieskończoną animację obrotu w onStart. W onStop czujnik jest wyłączany i animacja anulowana — zapobiega to zużyciu baterii przy ukrytym Activity. Po powrocie przez onRestart → onStart zasoby są odtwarzane.
Nowoczesne podejście z użyciem ViewModel + SavedStateHandle. Dane formularza są zapisywane automatycznie przy onStop bez ręcznego Bundle.
class FormViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
var email: String
get() = savedStateHandle["email"] ?: ""
set(value) { savedStateHandle["email"] = value }
var message: String
get() = savedStateHandle["message"] ?: ""
set(value) { savedStateHandle["message"] = value }
}
class FormActivity : AppCompatActivity() {
private val viewModel: FormViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_form)
Log.d("FormActivity", "onCreate: email=${viewModel.email}")
}
override fun onStop() {
super.onStop()
Log.d("FormActivity", "onStop: dane zapisane w SavedStateHandle")
}
}
SavedStateHandle automatycznie zapisuje wartości w Bundle przy onSaveInstanceState, które jest wywoływane przed onStop. Przy obrocie ekranu lub zabiciu procesu dane są przywracane bez utraty. Google zaleca SavedStateHandle dla formularzy i wersji roboczych zamiast bezpośredniego onSaveInstanceState.
Użycie lifecycleScope z korutynami do asynchronicznego zapisywania danych przy przejściu w onStop. Korutyna uruchamiana jest w dyspozytorze IO, nie blokując głównego wątku.
class NoteActivity : AppCompatActivity() {
private val noteRepository = NoteRepository()
override fun onStop() {
lifecycleScope.launch(Dispatchers.IO) {
val text = findViewById<EditText>(R.id.note_content).text.toString()
noteRepository.saveDraft(text)
withContext(Dispatchers.Main) {
Log.d("NoteActivity", "Wersja robocza zapisana w onStop")
}
}
super.onStop()
}
}
Korutyna lifecycleScope.launch jest automatycznie anulowana, jeśli cykl życia Activity się zakończy. Użycie Dispatchers.IO gwarantuje, że zapis w BD lub pliku nie blokuje powrotu do Activity. Według Google, korutyny w lifecycleScope — preferowany sposób asynchronicznych operacji w onStop.
Często zadawane pytania
onStop — Activity przestaje być widoczne, ale pozostaje w pamięci w stanie Stopped. System może przywrócić Activity przez onRestart. onDestroy — Activity jest niszczone, pamięć zwalniana. Po onDestroy powrót jest możliwy tylko przez utworzenie nowego wystąpienia Activity (onCreate).
Tak, obowiązkowe. super.onStop() zapewnia poprawne działanie komponentów systemowych: fragmentów, LoaderManager, ViewModelStore. Pominięcie super.onStop() może spowodować wycieki pamięci i nieprawidłowe przywracanie fragmentów. Zawsze wywołuj super.onStop() jako ostatnie lub pierwsze — kolejność nie jest krytyczna, ale wywołanie jest obowiązkowe.
Używaj Log.d lub Timber w każdej metodzie cyklu życia. Włącz filtr logcat według tagu swojego Activity. Dla produkcji używaj Android Vitals — Google automatycznie zbiera metryki cyklu życia i pokazuje anomalie w Play Console. Dostępny jest również monitoring cyklu życia przez ProcessLifecycleOwner.
Nieobsłużony wyjątek w onStop powoduje Force Close aplikacji. System nie przechwytuje wyjątków w callbackach cyklu życia. Jeśli w onStop wykonywane są operacje, które mogą zgłosić wyjątek (praca z plikami, siecią), otaczaj je try-catch i loguj błąd, nie przerywając wykonania super.onStop().
Nie, Bitmap w Activity zostanie zebrany przez GC, jeśli nie ma do niego referencji. Wymuszone zwalnianie (recycle()) w onStop nie jest wymagane i nawet szkodliwe — jeśli Activity wróci przez onRestart, Bitmap będzie trzeba załadować ponownie. Używaj Glide lub Coil do ładowania obrazów — te biblioteki automatycznie zarządzają pamięcią podręczną i cyklem życia.
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ż