onResume — to metoda cyklu życia Android, która jest wywoływana, gdy Activity lub Fragment przechodzi na pierwszy plan i otrzymuje fokus wejścia. W tym stanie ekran jest gotowy do interakcji z użytkownikiem: wszystkie zdarzenia dotykowe, naciśnięcia klawiszy i gesty są kierowane do tego komponentu. onResume to roboczy stan Activity, w którym aplikacja spędza większość czasu. To tutaj otwiera się kamerę, uruchamia odtwarzanie wideo, rozpoczyna rozpoznawanie mowy i rejestruje sensoryczne listenery, wymagające wyłącznego dostępu. Więcej o pełnym cyklu życia Activity przeczytasz w artykule Activity Lifecycle.
Najważniejsze
onResume — trzecia metoda cyklu życia Activity, wywoływana po onStart, która sygnalizuje gotowość ekranu do pełnej interakcji z użytkownikiem. W tym momencie Activity znajduje się na szczycie stosu zadań (back stack), system kieruje do niego wszystkie zdarzenia wejścia, a aplikacja może rozpoczynać dowolne operacje wymagające aktywnego udziału użytkownika: połączenia wideo, gry, nagrywanie dźwięku, rysowanie na Canvas.
onResume wchodzi w skład życia na pierwszym planie (foreground lifetime) — okres między onResume a onPause. To najbardziej aktywny okres pracy Activity, gdy aplikacja zużywa maksimum zasobów: procesor do obsługi dotknięć, GPU do renderowania animacji, kamerę i mikrofon do przechwytywania wideo. Zrozumienie tego poziomu cyklu życia jest krytyczne dla optymalizacji zużycia energii — zasoby otwarte w onResume muszą być natychmiast zamknięte w onPause.
Według danych Google I/O 2025, średni czas, jaki Activity spędza w stanie onResume podczas jednej sesji, wynosi 2–5 minut dla aplikacji informacyjnych i 15–30 minut dla gier i komunikatorów. Przez resztę czasu Activity znajduje się w stanach onPause, onStop lub onDestroy. Oznacza to, że optymalizacja właśnie kodu onResume daje największe korzyści w wydajności i czasie pracy baterii.
W Activity metoda onResume jest wywoływana za każdym razem, gdy ekran otrzymuje fokus wejścia — przy pierwszym uruchomieniu, przy powrocie z innego Activity, przy zamknięciu okna dialogowego, przy odblokowaniu urządzenia. To gorąca metoda, która może być wywoływana wiele razy podczas sesji, a jej implementacja powinna być maksymalnie lekka.
class CameraActivity : AppCompatActivity() {
private var cameraProvider: ProcessCameraProvider? = null
private var preview: Preview? = null
override fun onResume() {
super.onResume()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
cameraProvider = cameraProviderFuture.get()
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
preview = Preview.Builder().build().also {
it.setSurfaceProvider(binding?.viewFinder?.surfaceProvider)
}
try {
cameraProvider?.unbindAll()
cameraProvider?.bindToLifecycle(
this, cameraSelector, preview
)
} catch (e: Exception) {
Log.e("Camera", "Nie udało się powiązać kamery", e)
}
}, ContextCompact.getMainExecutor(this))
}
override fun onPause() {
super.onPause()
cameraProvider?.unbindAll()
preview = null
}
}
Przykład z CameraX demonstruje klasyczne użycie onResume/onPause: kamera to zasób wyłączny, który może być używany tylko przez jedną aplikację w danym momencie. Powiązanie kamery z cyklem życia przez bindToLifecycle automatycznie zamyka kamerę w onPause, ale jawne wywołanie unbindAll gwarantuje natychmiastowe zwolnienie. Jest to szczególnie ważne przy przełączaniu między Activity: kamera musi być zwolniona, zanim inne Activity spróbuje ją otworzyć.
onResume we Fragment jest wywoływane po tym, jak zawierające go Activity otrzymało onResume. Jednak ze względu na specyfikę FragmentManager i ViewPager moment wywołania onResume dla Fragment może być opóźniony względem Activity. Na przykład Fragment w ViewPager z offscreenPageLimit = 1 otrzymuje onResume dopiero gdy staje się bieżącą stroną, a nie przy starcie Activity.
class VideoPlayerFragment : Fragment() {
private var exoPlayer: ExoPlayer? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
exoPlayer = ExoPlayer.Builder(requireContext()).build()
binding?.playerView?.player = exoPlayer
}
override fun onResume() {
super.onResume()
exoPlayer?.play()
if (userVisibleHint) {
startBiometricAuth()
}
}
override fun onPause() {
exoPlayer?.pause()
stopBiometricAuth()
super.onPause()
}
}
Sprawdzenie userVisibleHint w Fragment.onResume jest istotne dla ViewPager: Fragment może otrzymać onResume, ale być ukryty przez sąsiednią stronę (na przykład przy animowanym przejściu). W takich przypadkach uruchomienie wideo lub biometrii w onResume bez sprawdzenia widoczności doprowadzi do nieoczekiwanego zachowania. Od Fragment 1.5.0 zaleca się używanie FragmentTransaction.setMaxLifecycle() do precyzyjnej kontroli cyklu życia fragmentów w ViewPager2.
Deweloperzy często mylą onStart i onResume, umieszczając kod w niewłaściwej metodzie. Główna zasada: onStart — dla zasobów działających przy widoczności; onResume — dla zasobów wymagających fokusu wejścia. Rozważmy konkretne scenariusze i prawidłowy wybór metody.
| Operacja | Metoda | Uzasadnienie |
|---|---|---|
| Subskrypcja geolokalizacji | onStart / onStop | GPS może działać przy częściowej widoczności |
| Otwieranie kamery | onResume / onPause | Kamera — zasób wyłączny ekskluzywny |
| BroadcastReceiver | onStart / onStop | Zdarzenia systemowe nie wymagają fokusu |
| Odtwarzanie wideo | onResume / onPause | Wideo musi być widoczne dla użytkownika |
| Skanowanie Bluetooth | onStart / onStop | Skanowanie może działać w tle |
| Dyktafon (MediaRecorder) | onResume / onPause | Nagrywanie wymaga aktywnego UI |
| Listenery sensorów | onResume / onPause | Czujniki do gier i gestów |
| Aktualizacja danych | onStart | Świeże dane potrzebne przy pojawieniu się |
Praktyczna zasada: jeśli operacja powinna być przerwana przy pojawieniu się okna dialogowego — używaj onResume/onPause. Jeśli operacja może być kontynuowana przy częściowym przesłonięciu ekranu — używaj onStart/onStop. Na przykład odtwarzacz wideo powinien wstrzymać wideo przy otwarciu okna dialogowego (onPause), a geolokalizacja może być aktualizowana (pozostaje w onStart).
Zasoby wyłączne to komponenty urządzenia, które mogą być używane tylko przez jedną aplikację w danym momencie. Kamera, mikrofon, wyjście wideo (MediaProjection), adapter NFC w trybie odczytu, urządzenia USB w trybie accessory — wszystkie te zasoby muszą być otwierane w onResume i zwalniane w onPause.
MediaRecorder jest używany do nagrywania audio i wideo. Prośba o uprawnienia i przygotowanie MediaRecorder odbywa się w onCreate, a start nagrywania — w onResume. Jeśli użytkownik przełącza się do innej aplikacji, onPause wstrzymuje nagrywanie, a onResume je wznawia. To standardowe zachowanie dla dyktafonów i aplikacji do nagrywania wideo.
private var mediaRecorder: MediaRecorder? = null
private var isRecording = false
override fun onResume() {
super.onResume()
if (isRecording) {
mediaRecorder?.resume()
}
}
override fun onPause() {
if (isRecording) {
mediaRecorder?.pause()
}
super.onPause()
}
Uwierzytelnianie biometryczne (BiometricPrompt) powinno być wywoływane tylko gdy Activity znajduje się w onResume. Jeśli wywołasz je w onCreate lub onStart, okno biometrii może pojawić się zanim Activity zakończy inicjalizację, co doprowadzi do nieprawidłowego przetwarzania wyniku. Wywołanie w onResume gwarantuje, że okno biometrii zostanie pokazane w prawidłowym kontekście.
Rozważmy trzy sprawdzone wzorce pracy z onResume, które są stosowane w projektach komercyjnych: resetowanie timera nieaktywności, aktualizacja widocznych danych i integracja z Jetpack Navigation.
W aplikacjach z poufnymi danymi (bankowość, karty medyczne) onResume jest używany do resetowania timera automatycznego wylogowania. Jeśli użytkownik aktywnie korzysta z aplikacji, onResume jest wywoływany przy każdym przejściu między ekranami i timer jest resetowany. Jeśli użytkownik zwinął aplikację, onPause zatrzymuje timer, a onResume przy powrocie albo go resetuje, albo żąda ponownego uwierzytelnienia.
Lista, która powinna wyświetlać aktualne dane przy każdym powrocie na ekran, jest aktualizowana w onResume. Na przykład, jeśli użytkownik utworzył nowy wpis w innym Activity i wrócił, onResume przeładowuje listę z lokalnej bazy danych lub z cache ViewModel. Zapewnia to spójność danych bez ręcznego wywoływania notifyDataSetChanged.
override fun onResume() {
super.onResume()
// ActivityResultLauncher zwrócił wynik — aktualizujemy listę
viewModel.refreshList()
// Resetowanie timera nieaktywności
inactivityTimer.reset()
}
W Jetpack Navigation onResume fragmentu jest wywoływany przy każdym powrocie do niego przez nawigację wsteczną. Ta właściwość jest używana do resetowania stanu UI: ukrycia klawiatury, wyczyszczenia pól wyszukiwania, aktualizacji nagłówka paska narzędzi. OnBackPressedCallback w połączeniu z onResume daje pełną kontrolę nad nawigacją bez duplikowania kodu.
Często zadawane pytania
onStart — ekran jest widoczny. onResume — ekran jest aktywny i gotowy do interakcji. Wyobraź sobie: oglądasz telewizję (onStart), ale bierzesz pilota w rękę (onResume). Telewizja jest cały czas widoczna, ale interakcja zaczyna się dopiero z pilotem. Jeśli ktoś zasłoni telewizor zasłoną — ekran przestaje być widoczny (onStop). Jeśli odbiorą ci pilota — interakcja się kończy (onPause), ale telewizor wciąż jest widoczny.
onResume jest wywoływany za każdym razem, gdy Activity otrzymuje fokus wejścia. Minimalna liczba — jeden raz (przy uruchomieniu). Maksymalna zależy od scenariuszy użycia: przełączanie między ekranami, otwieranie okien dialogowych, szybkie blokowanie i odblokowywanie urządzenia — każdy taki scenariusz wywołuje onResume przy powrocie na ekran.
Kamera to zasób wyłączny dostępny tylko dla jednej aplikacji w danym momencie. Jeśli otworzysz kamerę w onCreate lub onStart, pozostanie ona zablokowana dla innych aplikacji nawet gdy twoja aplikacja jest nieaktywna. onResume gwarantuje, że kamera jest otwarta tylko gdy Activity znajduje się na pierwszym planie, a onPause natychmiast ją zamyka. To standard programowania Android, utrwalony w dokumentacji CameraX i Camera2 API.
Tak, onResume może nie nastąpić, jeśli Activity zostanie przesłonięte przez inne Activity zaraz po pojawieniu się. Na przykład Activity A uruchamia Activity B w metodzie onCreate lub onStart. W tym przypadku A otrzymuje onStart → onPause → onStop, pomijając onResume. System nie wywołuje onResume, ponieważ Activity A nigdy nie otrzymało fokusu wejścia.
W onResume nie wolno wykonywać długich synchronizacyjnych operacji: ładowanie dużych danych z sieci, złożone zapytania SQL, przetwarzanie obrazów. Metoda onResume działa w wątku UI, a każde zablokowanie dłuższe niż 100–200 ms prowadzi do opóźnienia responsywności interfejsu. Wszystkie ciężkie operacje powinny być asynchroniczne — przez korutyny, RxJava lub WorkManager. Nie zaleca się również wywoływania finish() w onResume bez sprawdzenia — może to prowadzić do nieskończonej pętli odtwarzania.
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ż