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 — 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.
// 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.
lifecycleScope jest dostępny wszędzie tam, gdzie jest LifecycleOwner:
Mechanizm automatycznego anulowania lifecycleScope opiera się na subskrypcji zdarzeń Lifecycle. Gdy Lifecycle spada poniżej CREATED do DESTROYED, scope jest anulowany.
| Stan | Opis | Scope aktywny |
|---|---|---|
| CREATED | LifecycleOwner utworzony, onCreate wykonany | Tak |
| STARTED | LifecycleOwner widoczny (onStart) | Tak |
| RESUMED | LifecycleOwner na pierwszym planie (onResume) | Tak |
| DESTROYED | LifecycleOwner zniszczony (onDestroy) | Nie (scope anulowany) |
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.
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.
Biblioteka lifecycle dostarcza kilka sposobów uruchamiania korutyn przez lifecycleScope. Prześledźmy ewolucję API od przestarzałych metod do nowoczesnych.
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.
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ż:
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.
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.
Do zbierania danych z Flow z uwzględnieniem cyklu życia istnieje operator flowWithLifecycle. Automatycznie zatrzymuje i wznawia zbieranie przy zmianie stanu Lifecycle:
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.
Rozważmy trzy rzeczywiste scenariusze zastosowania lifecycleScope w aplikacji Android w Kotlinie.
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.
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.
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.
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.
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.
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.
Rozważmy cztery najczęstsze błędy, które popełniają programiści przy użyciu lifecycleScope.
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.
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.
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.
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
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.
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.
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.
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.
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
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ż