onStop — co to jest, ukrywanie Activity w cyklu życia Androida

Autor: IT Sectr Opublikowano: 2026-03-04 Czas czytania: 9 min

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 — metoda wywoływana przy całkowitej utracie widoczności Activity, ale Activity nadal znajduje się w pamięci.
  • Po onStop Activity przechodzi w stan Stopped — żyje w pamięci, ale nie jest widoczne i nie wchodzi w interakcję z użytkownikiem.
  • System może wywołać onRestart → onStart → onResume przy powrocie do Activity lub onDestroy przy zakończeniu.
  • W onStop należy zwolnić zasoby: zatrzymać animacje, wyłączyć czujniki i kamerę, zapisać dane tymczasowe.
  • Poprawna implementacja onStop — kluczowy czynnik stabilności aplikacji przy wielozadaniowości i minimalizowaniu.

Czym jest onStop w Androidzie?

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.

Kiedy wywoływane jest onStop: scenariusze i kolejność

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:

  • Uruchomienie nowego Activity nad bieżącym — bieżące Activity otrzymuje onPause, następnie onStop; nowe Activity przechodzi onCreate → onStart → onResume.
  • Zminimalizowanie aplikacji (Home) — Activity przechodzi w onPause → onStop w ciągu 200–300 ms, pozostaje w pamięci w stanie Stopped.
  • Blokada ekranu — system wywołuje onPause → onStop, ponieważ ekran blokady całkowicie zasłania Activity.
  • Przychodzące połączenie — Activity telefonu (Dialer) uruchamia się na wierzchu, bieżące Activity przechodzi w onStop.
  • Przełączenie na inną aplikację (Recent Apps) — Activity jest ukrywane, otrzymuje onStop, ale pozostaje w pamięci podręcznej procesów.

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 w cyklu życia Activity

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).

StanMetodaWidocznośćInterakcjaPamięć
CreatedonCreateNieNieAlokowana
StartedonStartCięściowoNiePełna
ResumedonResumePełnaTakPełna
PausedonPauseCięściowoNiePełna
StoppedonStopNieNiePełna*
DestroyedonDestroyNieNieZwolniona

*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.

Jakie zasoby zwalniać w onStop

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:

  • Animacje i transitions — zatrzymać ObjectAnimator, ValueAnimator, ViewPropertyAnimator. Działająca animacja niewidocznego Activity to marnowanie cykli GPU.
  • Czujniki (Sensors) — wypisać się z SensorManager (akcelerometr, żyroskop, magnetometr). Czujniki pobierają energię nawet przy ukrytym Activity.
  • Aparat i mikrofon — zwolnić Camera2 lub CameraX, zatrzymać MediaRecorder. Pozostawianie aparatu aktywnego przy ukrytym Activity jest zabronione przez politykę Google Play.
  • LocationListener — wypisać się z FusedLocationProviderClient lub LocationManager. Geolokalizacja — najbardziej energochłonny zasób.
  • Network listeners — zamknąć WebSocket, anulować żądania HTTP, które nie są potrzebne w tle.
  • MediaPlayer i ExoPlayer — wstrzymać lub zatrzymać, jeśli odtwarzanie nie powinno być kontynuowane w tle.

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.

Różnica między onStop a onPause

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.

CharakterystykaonPauseonStop
Stopień widocznościCięściowo widoczneCałkowicie niewidoczne
FokusUtraconyUtracony
Czas wykonaniaDo 500 msDo 5 s (ANR-timeout)
Zasoby do zwolnieniaKrytyczne (media, aparat)Wszystkie niewidoczne (czujniki, animacje, location)
PrzywrócenieonResumeonRestart → onStart → onResume
Priorytet procesuWysoki (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.

onStop → onRestart: powrót na ekran

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:

  • onRestart() — Activity jest powiadamiane, że zostanie ponownie pokazane. Typowe działania: przeładowanie danych, aktualizacja list.
  • onStart() — Activity staje się widoczne, ale jeszcze nie aktywne. Tutaj ponownie inicjalizowane są zasoby zwolnione w onStop.
  • onResume() — Activity otrzymuje fokus i jest gotowe do interakcji. Uruchamiane są animacje, rejestrowane czujniki.

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.

Przykłady kodu z onStop w Kotlin

Przykład 1: Podstawowa implementacja onStop z zwalnianiem czujników

Pokazuje poprawne wypisanie się z czujników i zatrzymanie animacji przy ukrywaniu Activity. Po powrocie na ekran zasoby są przywracane w onStart.

kotlin
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.

Przykład 2: onStop z zapisywaniem stanu przez SavedStateHandle

Nowoczesne podejście z użyciem ViewModel + SavedStateHandle. Dane formularza są zapisywane automatycznie przy onStop bez ręcznego Bundle.

kotlin
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.

Przykład 3: lifecycleScope dla operacji w onStop

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.

kotlin
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

Czym różni się onStop od onDestroy?

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).

Czy obowiązkowe jest wywołanie super.onStop()?

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.

Jak sprawdzić, czy onStop został wywołany?

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.

Co się stanie, jeśli w onStop zostanie zgłoszony wyjątek?

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().

Czy trzeba zwalniać Bitmap w 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

  • onStop — metoda cyklu życia Activity, wywoływana przy całkowitej utracie widoczności. Activity pozostaje w pamięci w stanie Stopped.
  • Po onStop możliwe są dwa scenariusze: onRestart (powrót na ekran) lub onDestroy (zniszczenie Activity).
  • W onStop należy zwolnić czujniki, animacje, aparat, location-listenery — wszystko, co nie jest potrzebne przy niewidocznym Activity.
  • onStop różni się od onPause stopniem widoczności: onPause — częściowa, onStop — całkowita utrata widoczności.
  • onSaveInstanceState jest wywoływane przed onStop — używaj go do zapisywania przejściowego stanu UI.
  • Korutyny lifecycleScope z Dispatchers.IO — preferowany sposób asynchronicznych operacji w onStop.
  • Zawsze wywołuj super.onStop() i otaczaj niebezpieczne operacje try-catch, aby uniknąć Force Close.

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.

Omów projekt

Przeczytaj również