lifecycleScope — co to jest, powiązanie z Lifecycle i praca w Androidzie

Autor: IT Sectr Opublikowano: 2026-06-23 Czas czytania: 9 min

lifecycleScope — to wbudowany CoroutineScope z biblioteki androidx.lifecycle, który jest powiązany z cyklem życia Activity, Fragment lub dowolnego LifecycleOwner i automatycznie anuluje korutyny przy zniszczeniu komponentu. Według Google Android Developers, 2025, lifecycleScope pozwala bezpiecznie uruchamiać korutyny związane z warstwą UI bez ryzyka wykonania kodu po zniszczeniu Activity lub Fragment. Scope automatycznie anuluje się przy przejściu LifecycleOwner w stan DESTROYED.

Najważniejsze

  • lifecycleScope — CoroutineScope z lifecycle-runtime-ktx, anulowany przy stanie DESTROYED Lifecycle
  • lifecycleScope.launch — uruchomienie korutyny, która automatycznie anuluje się przy zniszczeniu LifecycleOwner
  • launchWhenStarted / launchWhenResumed — przestarzałe metody, zastąpione przez repeatOnLifecycle
  • repeatOnLifecycle — nowoczesne API do uruchamiania korutyn śledzących konkretny stan Lifecycle
  • Dispatchers.Main.immediate — domyślny dyspozytor dla lifecycleScope

Czym jest lifecycleScope w Androidzie?

lifecycleScope — to właściwość rozszerzająca interfejs LifecycleOwner (Activity, Fragment, Service), dostarczająca gotowy CoroutineScope powiązany z pełnym cyklem życia komponentu. Gdy LifecycleOwner osiąga stan DESTROYED, lifecycleScope automatycznie anuluje wszystkie aktywne korutyny.

kotlin
// W Fragment lub Activity
lifecycleScope.launch {
    delay(1000)
    showSnackbar("Witaj!")
}

W przeciwieństwie do viewModelScope, lifecycleScope anuluje się przy każdym zniszczeniu LifecycleOwner — włączając rotację ekranu. To czyni go idealnym dla operacji, które powinny żyć tylko gdy konkretny ekran jest widoczny.

Gdzie dostępny jest lifecycleScope

lifecycleScope jest dostępny wszędzie tam, gdzie jest LifecycleOwner:

  • Activity — AppCompatActivity dziedziczy po LifecycleOwner
  • Fragment — Fragment dziedziczy po LifecycleOwner
  • LifecycleService — usługa z cyklem życia
  • ProcessLifecycleOwner — cykl życia całej aplikacji
  • Niestandardowe LifecycleOwner — dowolne obiekty implementujące LifecycleOwner

Jak działa lifecycleScope: Lifecycle i automatyczne anulowanie

Mechanizm automatycznego anulowania lifecycleScope opiera się na subskrypcji zdarzeń Lifecycle. Gdy Lifecycle spada poniżej CREATED do DESTROYED, scope jest anulowany.

Stany Lifecycle

StanOpisScope aktywny
CREATEDLifecycleOwner utworzony, onCreate wykonanyTak
STARTEDLifecycleOwner widoczny (onStart)Tak
RESUMEDLifecycleOwner na pierwszym planie (onResume)Tak
DESTROYEDLifecycleOwner zniszczony (onDestroy)Nie (scope anulowany)

Wewnętrzna budowa lifecycleScope

lifecycleScope jest tworzony jako CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) i przechowywany wewnątrz Lifecycle. Przy przejściu Lifecycle w stan DESTROYED wywoływane jest scope.cancel(). Mechanizm jest zaimplementowany przez LifecycleEventObserver, który subskrybuje zdarzenia cyklu życia przy pierwszym dostępie do scope.

Zachowanie przy rotacji

Przy obrocie ekranu Activity jest niszczone (onDestroy) i tworzone od nowa. lifecycleScope jest anulowany wraz ze starą Activity, a nowa instancja scope jest tworzona dla nowej Activity. To zasadnicza różnica w stosunku do viewModelScope, który zachowuje się przy rotacji.

API lifecycleScope: launch, launchWhen i repeatOnLifecycle

Biblioteka lifecycle dostarcza kilka sposobów uruchamiania korutyn przez lifecycleScope. Prześledźmy ewolucję API od przestarzałych metod do nowoczesnych.

lifecycleScope.launch — podstawowe uruchomienie

Najprostszy sposób — lifecycleScope.launch { ... }. Korutyna uruchamia się natychmiast i anuluje przy DESTROYED. Może jednak wykonywać kod nawet gdy UI jest niewidoczne (np. w tle po onStop). Nie zawsze jest to pożądane.

Przestarzałe: launchWhenCreated / launchWhenStarted / launchWhenResumed

Te metody wstrzymywały wykonanie korutyny, gdy Lifecycle spadał poniżej określonego stanu, i wznawiały przy powrocie. Zostały jednak oznaczone jako @Deprecated w lifecycle-runtime-ktx 2.6.0, ponieważ:

  • Nie anulowały korutyny — tylko wstrzymywały
  • Prowadziły do gromadzenia wiszących korutyn zużywających pamięć
  • Tworzyły race condition przy szybkim przełączaniu stanów

Nowoczesne API: repeatOnLifecycle

repeatOnLifecycle — zalecany przez Google sposób uruchamiania korutyn synchronizowanych z cyklem życia. Anuluje i restartuje korutynę za każdym razem, gdy Lifecycle osiąga określony stan.

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiState.collect { state ->
            updateUI(state)
        }
    }
}

Korutyna przekazana do repeatOnLifecycle uruchamia się gdy Lifecycle osiąga STARTED i anuluje gdy spada poniżej STARTED. Przy powrocie do STARTED korutyna restartuje się od nowa. Jest to bezpieczne i wydajne — żadne korutyny nie wiszą w pauzie.

flowWithLifecycle — dla Flow

Do zbierania danych z Flow z uwzględnieniem cyklu życia istnieje operator flowWithLifecycle. Automatycznie zatrzymuje i wznawia zbieranie przy zmianie stanu Lifecycle:

kotlin
viewModel.uiState
    .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
    .onEach { state -> updateUI(state) }
    .launchIn(lifecycleScope)

Operator flowWithLifecycle — najbardziej zwięzły sposób bezpiecznej subskrypcji Flow w warstwie UI.

Przykłady użycia lifecycleScope

Rozważmy trzy rzeczywiste scenariusze zastosowania lifecycleScope w aplikacji Android w Kotlinie.

Przykład 1: Subskrypcja aktualizacji lokalizacji tylko gdy ekran jest widoczny

kotlin
class MapFragment : Fragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                locationProvider.observeLocation().collect { loc ->
                    updateMapMarker(loc)
                }
            }
        }
    }
}

Korutyna startuje gdy fragment staje się widoczny (STARTED) i anuluje gdy znika z ekranu (STOPPED). Jeśli użytkownik przełączy się na inną aplikację, aktualizacje lokalizacji nie zużywają baterii.

Przykład 2: Uruchamianie animacji przy starcie fragmentu

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.RESUMED) {
        animateFadeIn(titleView)
        delay(200)
        animateSlideUp(contentView)
    }
}

Animacja uruchamia się tylko gdy fragment jest na pierwszym planie (RESUMED). Jeśli użytkownik zwinie aplikację podczas animacji, korutyna jest anulowana, a przy powrocie animacja uruchamia się od nowa.

Przykład 3: Okresowa synchronizacja danych na widocznym ekranie

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        while (isActive) {
            syncData()
            delay(30_000L)
        }
    }
}

Dane są synchronizowane co 30 sekund, ale tylko gdy ekran jest widoczny. isActive sprawdza, czy korutyna nie została anulowana, co zapewnia możliwość bezpiecznego wyjścia z pętli przy opuszczeniu ekranu.

lifecycleScope vs viewModelScope: scenariusze zastosowania

Oba scope są powiązane z cyklem życia, ale z różnymi jego aspektami. Zrozumienie różnicy jest krytyczne dla prawidłowej architektury aplikacji Android.

Kluczowa różnica

viewModelScope jest powiązany z ViewModel, który przetrwa rotację ekranu. lifecycleScope jest powiązany z LifecycleOwner (Activity/Fragment), który przy rotacji jest niszczony i tworzony od nowa. To określa scenariusze ich zastosowania.

Kiedy używać lifecycleScope

  • Subskrypcja zdarzeń systemowych (lokalizacja, czujniki, kamera)
  • Animacje i efekty UI powiązane z konkretnym ekranem
  • Segmentowe ładowanie danych z uwzględnieniem widoczności ekranu
  • Operacje, które powinny się zakończyć przy opuszczeniu ekranu

Kiedy używać viewModelScope

  • Ładowanie danych z repozytorium
  • Logika biznesowa, która powinna przetrwać rotację
  • Buforowanie i przetwarzanie danych
  • Wszelkie operacje, których wynik jest potrzebny po rotacji

Łączne użycie

W praktyce często spotyka się kombinację obu scope: viewModelScope ładuje dane i zarządza stanem, lifecycleScope subskrybuje Flow z ViewModel z uwzględnieniem cyklu życia ekranu. To rozdzielenie odpowiedzialności uważane jest za best practice w nowoczesnym programowaniu na Androida.

Typowe błędy przy pracy z lifecycleScope

Rozważmy cztery najczęstsze błędy, które popełniają programiści przy użyciu lifecycleScope.

Błąd 1: Używanie lifecycleScope zamiast viewModelScope do ładowania danych

Jeśli uruchomisz ładowanie danych w lifecycleScope.launch, przy rotacji ekranu korutyna zostanie anulowana, a dane trzeba będzie ładować od nowa. Używaj viewModelScope do długotrwałych operacji. lifecycleScope — tylko dla zadań związanych z UI.

Błąd 2: Zbieranie Flow bez repeatOnLifecycle

Bezpośrednie wywołanie viewModel.someFlow.collect { ... } wewnątrz lifecycleScope.launch kontynuuje zbieranie danych nawet gdy ekran jest niewidoczny. Może to prowadzić do aktualizacji UI w tle i zbędnych narzutów. Zawsze używaj repeatOnLifecycle lub flowWithLifecycle.

Błąd 3: Zapomnienie o anulowaniu przy opuszczeniu ekranu

Mimo że lifecycleScope anuluje się przy DESTROYED, kod po punkcie wstrzymania (suspend) może nie wykonać się przy nagłym anulowaniu. Nie polegaj na wykonaniu kodu po wywołaniu suspend, chyba że używasz NonCancellable.

Błąd 4: Używanie przestarzałego launchWhenStarted zamiast repeatOnLifecycle

launchWhenStarted i jego odpowiedniki nie anulują korutyny, a tylko wstrzymują. Jeśli ekran wielokrotnie przełącza się między pierwszym a drugim planem, korutyna gromadzi odroczone wywołania. Przejdź na repeatOnLifecycle — to jedyny prawidłowy sposób synchronizacji z Lifecycle.

Często zadawane pytania

Jaka jest różnica między lifecycleScope a GlobalScope?

lifecycleScope automatycznie anuluje się przy zniszczeniu LifecycleOwner. GlobalScope żyje przez cały czas działania aplikacji. Korutyna w lifecycleScope nie może aktualizować UI po zniszczeniu komponentu, w GlobalScope — może, co prowadzi do błędów. Zawsze używaj lifecycleScope w warstwie UI.

Czy można używać lifecycleScope w ViewModel?

Nie, ViewModel nie jest LifecycleOwner, więc lifecycleScope nie jest w nim dostępny. ViewModel używa viewModelScope. Jeśli kod ma być wykonywany w obu kontekstach — wydziel logikę do use case lub repozytorium z funkcjami suspend.

Co się stanie przy ponownym wywołaniu repeatOnLifecycle?

Każde wywołanie repeatOnLifecycle tworzy nową korutynę, która uruchamia blok po osiągnięciu określonego stanu Lifecycle. Jeśli wywołasz repeatOnLifecycle dwukrotnie dla tego samego stanu, oba bloki zostaną uruchomione niezależnie. Zazwyczaj wystarczy jedno wywołanie w onViewCreated.

Czy można ustawić niestandardowy Dispatcher dla lifecycleScope?

Bezpośrednio zmienić dyspozytora lifecycleScope nie można — używa on Dispatchers.Main.immediate. Wewnątrz bloku korutyny można przełączyć się na inny dyspozytor przez withContext. Do testów używaj TestDispatcher z LifecycleOwner.

Czy lifecycleScope anuluje się w onPause czy onDestroy?

lifecycleScope anuluje się przy przejściu LifecycleOwner w stan DESTROYED (po onDestroy). Zwykłe wywołania lifecycleScope.launch nie anulują się w onPause lub onStop. Do wstrzymania przy przejściu w tło używaj repeatOnLifecycle(STARTED) lub repeatOnLifecycle(RESUMED).

Podsumowanie

  • lifecycleScope — CoroutineScope powiązany z LifecycleOwner, automatycznie anulowany przy DESTROYED przez LifecycleEventObserver
  • Dispatchers.Main.immediate — domyślny dyspozytor zapewniający bezpieczną aktualizację UI bez zbędnych przełączeń
  • repeatOnLifecycle — nowoczesne API do uruchamiania korutyn w określonym stanie Lifecycle z automatycznym anulowaniem i restartem
  • flowWithLifecycle — operator do bezpiecznego zbierania Flow z UI z uwzględnieniem cyklu życia
  • launchWhenStarted jest przestarzały — zamiast wstrzymywania używaj repeatOnLifecycle, który anuluje korutynę, a nie wstrzymuje
  • lifecycleScope vs viewModelScope — lifecycleScope do operacji UI (animacje, lokalizacja), viewModelScope do danych i logiki biznesowej
  • Rotacja ekranu — lifecycleScope anuluje się przy rotacji, viewModelScope zachowuje; wybieraj scope w zależności od zadania

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ż