lifecycleScope — je vestavěný CoroutineScope z knihovny androidx.lifecycle, který je připojen k životnímu cyklu Activity, Fragment nebo jakéhokoli LifecycleOwner a automaticky ruší korutiny při zničení komponenty. Podle Google Android Developers, 2025 umožňuje lifecycleScope bezpečně spouštět korutiny spojené s vrstvou UI bez rizika provedení kódu po zničení Activity nebo Fragmentu. Scope se automaticky zruší při přechodu LifecycleOwner do stavu DESTROYED.
Hlavní body
lifecycleScope — je rozšiřující vlastnost na rozhraní LifecycleOwner (Activity, Fragment, Service), která poskytuje hotový CoroutineScope připojený k plnému životnímu cyklu komponenty. Když LifecycleOwner dosáhne stavu DESTROYED, lifecycleScope automaticky zruší všechny aktivní korutiny.
// Ve Fragment nebo Activity
lifecycleScope.launch {
delay(1000)
showSnackbar("Ahoj!")
}
Na rozdíl od viewModelScope se lifecycleScope ruší při každém zničení LifecycleOwner — včetně rotace obrazovky. To jej činí ideálním pro operace, které by měly žít pouze dokud je konkrétní obrazovka viditelná.
lifecycleScope je dostupný všude tam, kde je LifecycleOwner:
Mechanismus automatického rušení lifecycleScope je založen na odběru událostí Lifecycle. Když Lifecycle klesne pod CREATED do DESTROYED, scope je zrušen.
| Stav | Popis | Scope aktivní |
|---|---|---|
| CREATED | LifecycleOwner vytvořen, onCreate proveden | Ano |
| STARTED | LifecycleOwner viditelný (onStart) | Ano |
| RESUMED | LifecycleOwner v popředí (onResume) | Ano |
| DESTROYED | LifecycleOwner zničen (onDestroy) | Ne (scope zrušen) |
lifecycleScope je vytvořen jako CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) a uložen uvnitř Lifecycle. Při přechodu Lifecycle do stavu DESTROYED je voláno scope.cancel(). Mechanismus je implementován prostřednictvím LifecycleEventObserver, který se přihlásí k odběru událostí životního cyklu při prvním přístupu ke scope.
Při rotaci obrazovky je Activity zničeno (onDestroy) a znovu vytvořeno. lifecycleScope je zrušen spolu se starou Activity a pro novou Activity je vytvořena nová instance scope. To je zásadní rozdíl oproti viewModelScope, který je při rotaci zachován.
Knihovna lifecycle poskytuje několik způsobů spouštění korutin prostřednictvím lifecycleScope. Podívejme se na vývoj API od zastaralých metod k moderním.
Nejjednodušší způsob — lifecycleScope.launch { ... }. Korutina se spustí okamžitě a zruší se při DESTROYED. Může však vykonávat kód i když UI není viditelné (např. na pozadí po onStop). To není vždy žádoucí.
Tyto metody pozastavovaly provádění korutiny, když Lifecycle klesl pod určený stav, a obnovovaly při návratu. Byly však označeny jako @Deprecated v lifecycle-runtime-ktx 2.6.0, protože:
repeatOnLifecycle — doporučený způsob Google pro spouštění korutin synchronizovaných s životním cyklem. Ruší a restartuje korutinu pokaždé, když Lifecycle dosáhne určeného stavu.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
}
Korutina předaná do repeatOnLifecycle se spustí když Lifecycle dosáhne STARTED a zruší se když klesne pod STARTED. Při návratu do STARTED se korutina restartuje od začátku. To je bezpečné a efektivní — žádné korutiny nevisí v pauze.
Pro sběr dat z Flow s ohledem na životní cyklus existuje operátor flowWithLifecycle. Automaticky zastavuje a obnovuje sběr při změně stavu Lifecycle:
viewModel.uiState
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.onEach { state -> updateUI(state) }
.launchIn(lifecycleScope)
Operátor flowWithLifecycle — nejstručnější způsob bezpečného odběru Flow ve vrstvě UI.
Podívejme se na tři reálné scénáře použití lifecycleScope v Android aplikaci v 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)
}
}
}
}
}
Korutina startuje když se fragment stane viditelným (STARTED) a ruší se když opustí obrazovku (STOPPED). Pokud uživatel přepne na jinou aplikaci, aktualizace polohy nespotřebovávají baterii.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
animateFadeIn(titleView)
delay(200)
animateSlideUp(contentView)
}
}
Animace se spouští pouze když je fragment v popředí (RESUMED). Pokud uživatel minimalizuje aplikaci během animace, korutina je zrušena a při návratu se animace spustí znovu.
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
while (isActive) {
syncData()
delay(30_000L)
}
}
}
Data jsou synchronizována každých 30 sekund, ale pouze když je obrazovka viditelná. isActive kontroluje, zda korutina nebyla zrušena, což zajišťuje bezpečný výstup z cyklu při opuštění obrazovky.
Oba scopes jsou připojeny k životnímu cyklu, ale k jeho různým aspektům. Pochopení rozdílu je kritické pro správnou architekturu Android aplikací.
viewModelScope je připojen k ViewModel, který přežije rotaci obrazovky. lifecycleScope je připojen k LifecycleOwner (Activity/Fragment), který se při rotaci ničí a znovu vytváří. To určuje scénáře jejich použití.
V praxi se často setkáváme s kombinací obou scope: viewModelScope načítá data a spravuje stav, lifecycleScope odebírá Flow z ViewModel s ohledem na životní cyklus obrazovky. Toto rozdělení odpovědnosti je považováno za best practice v moderním Android vývoji.
Podívejme se na čtyři nejčastější chyby, kterých se vývojáři dopouštějí při používání lifecycleScope.
Pokud spustíte načítání dat v lifecycleScope.launch, při rotaci obrazovky dojde ke zrušení korutiny a data bude nutné načíst znovu. Používejte viewModelScope pro dlouhotrvající operace. lifecycleScope — pouze pro úkoly související s UI.
Přímé volání viewModel.someFlow.collect { ... } uvnitř lifecycleScope.launch pokračuje ve sběru dat i když obrazovka není viditelná. To může vést k aktualizacím UI na pozadí a zbytečné režii. Vždy používejte repeatOnLifecycle nebo flowWithLifecycle.
Ačkoli se lifecycleScope ruší při DESTROYED, kód po bodu pozastavení (suspend) se nemusí provést při náhlém zrušení. Nespoléhejte na provedení kódu po volání suspend, pokud nepoužíváte NonCancellable.
launchWhenStarted a jeho analogy korutinu neruší, pouze ji pozastavují. Pokud obrazovka mnohokrát přepíná mezi popředím a pozadím, korutina hromadí odložená volání. Přepněte na repeatOnLifecycle — to je jediný správný způsob synchronizace s Lifecycle.
Často kladené otázky
lifecycleScope se automaticky ruší při zničení LifecycleOwner. GlobalScope žije po celou dobu běhu aplikace. Korutina v lifecycleScope nemůže aktualizovat UI po zničení komponenty, v GlobalScope může, což vede k pádům. Vždy používejte lifecycleScope ve vrstvě UI.
Ne, ViewModel není LifecycleOwner, takže lifecycleScope v něm není dostupný. ViewModel používá viewModelScope. Pokud má být kód spouštěn v obou kontextech — vyčleňte logiku do use case nebo repository se suspend funkcemi.
Každé volání repeatOnLifecycle vytváří novou korutinu, která spouští blok při dosažení určeného stavu Lifecycle. Pokud je repeatOnLifecycle volán dvakrát pro stejný stav, oba bloky poběží nezávisle. Obvykle stačí jedno volání v onViewCreated.
Přímo změnit dispečer lifecycleScope nelze — používá Dispatchers.Main.immediate. Uvnitř bloku korutiny se můžete přepnout na jiný dispečer pomocí withContext. Pro testy používejte TestDispatcher s LifecycleOwner.
lifecycleScope se ruší při přechodu LifecycleOwner do stavu DESTROYED (po onDestroy). Jednoduchá volání lifecycleScope.launch se neruší v onPause nebo onStop. Pro pozastavení při přechodu na pozadí použijte repeatOnLifecycle(STARTED) nebo repeatOnLifecycle(RESUMED).
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také