lifecycleScope — cos’è, associazione al Lifecycle e lavoro in Android

Autore: IT Sectr Pubblicato: 2026-06-23 Tempo di lettura: 9 min

lifecycleScope è un CoroutineScope integrato della libreria androidx.lifecycle, legato al ciclo di vita di un’Activity, di un Fragment o di qualsiasi LifecycleOwner, e annulla automaticamente le coroutine quando il componente viene distrutto. Secondo Google Android Developers, 2025, lifecycleScope consente di eseguire in sicurezza le coroutine legate al livello UI senza il rischio di eseguire codice dopo la distruzione dell’Activity o del Fragment. Lo scope viene automaticamente annullato quando il LifecycleOwner passa allo stato DESTROYED.

Punti chiave

  • lifecycleScope — CoroutineScope da lifecycle-runtime-ktx, annullato allo stato DESTROYED del Lifecycle
  • lifecycleScope.launch — avvia una coroutine che viene automaticamente annullata quando il LifecycleOwner viene distrutto
  • launchWhenStarted / launchWhenResumed — metodi obsoleti, sostituiti da repeatOnLifecycle
  • repeatOnLifecycle — API moderna per avviare coroutine che seguono uno stato specifico del Lifecycle
  • Dispatchers.Main.immediate — dispatcher predefinito per lifecycleScope

Cos’è lifecycleScope in Android?

lifecycleScope è una proprietà di estensione sull’interfaccia LifecycleOwner (Activity, Fragment, Service) che fornisce un CoroutineScope pronto all’uso, legato al ciclo di vita completo del componente. Quando il LifecycleOwner raggiunge lo stato DESTROYED, lifecycleScope annulla automaticamente tutte le coroutine attive.

kotlin
// In Fragment or Activity
lifecycleScope.launch {
    delay(1000)
    showSnackbar("Ciao!")
}

A differenza di viewModelScope, lifecycleScope viene annullato ogni volta che il LifecycleOwner viene distrutto — inclusa la rotazione dello schermo. Questo lo rende ideale per operazioni che dovrebbero vivere solo finché un determinato schermo è visibile.

Dove è disponibile lifecycleScope

lifecycleScope è disponibile ovunque ci sia un LifecycleOwner:

  • Activity — AppCompatActivity eredita LifecycleOwner
  • Fragment — Fragment eredita LifecycleOwner
  • LifecycleService — un servizio con ciclo di vita
  • ProcessLifecycleOwner — il ciclo di vita dell’intera applicazione
  • LifecycleOwner personalizzato — qualsiasi oggetto che implementi LifecycleOwner

Come funziona lifecycleScope: Lifecycle e cancellazione automatica

Il meccanismo di cancellazione automatica di lifecycleScope si basa sull’iscrizione agli eventi Lifecycle. Quando il Lifecycle scende al di sotto di CREATED verso DESTROYED, lo scope viene annullato.

Stati del Lifecycle

StatoDescrizioneScope attivo
CREATEDLifecycleOwner creato, onCreate eseguito
STARTEDLifecycleOwner visibile (onStart)
RESUMEDLifecycleOwner in primo piano (onResume)
DESTROYEDLifecycleOwner distrutto (onDestroy)No (scope annullato)

Struttura interna di lifecycleScope

lifecycleScope viene creato come CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) e memorizzato all’interno del Lifecycle. Quando il Lifecycle passa allo stato DESTROYED, viene chiamato scope.cancel(). Il meccanismo è implementato tramite LifecycleEventObserver, che si iscrive agli eventi del ciclo di vita al primo accesso allo scope.

Comportamento durante la rotazione

Quando lo schermo viene ruotato, l’Activity viene distrutta (onDestroy) e ricreata. lifecycleScope viene annullato insieme alla vecchia Activity e viene creata una nuova istanza dello scope per la nuova Activity. Questa è una differenza fondamentale rispetto a viewModelScope, che sopravvive alla rotazione.

API di lifecycleScope: launch, launchWhen e repeatOnLifecycle

La libreria lifecycle fornisce diversi modi per avviare coroutine tramite lifecycleScope. Esaminiamo l’evoluzione dell’API dai metodi obsoleti a quelli moderni.

lifecycleScope.launch — Avvio di base

Il modo più semplice è lifecycleScope.launch { ... }. La coroutine si avvia immediatamente e viene annullata a DESTROYED. Tuttavia, può eseguire codice anche quando l’UI non è visibile (ad esempio, in background dopo onStop). Ciò non è sempre desiderabile.

Obsoleti: launchWhenCreated / launchWhenStarted / launchWhenResumed

Questi metodi mettevano in pausa l’esecuzione della coroutine quando il Lifecycle scendeva al di sotto dello stato specificato e la riprendevano al ritorno. Tuttavia, sono stati contrassegnati come @Deprecated in lifecycle-runtime-ktx 2.6.0 perché:

  • Non annullavano la coroutine — la mettevano solo in pausa
  • Portavano all’accumulo di coroutine sospese che consumano memoria
  • Creavano condizioni di gara durante cambiamenti rapidi di stato

API moderna: repeatOnLifecycle

repeatOnLifecycle è il metodo consigliato da Google per avviare coroutine sincronizzate con il ciclo di vita. Annulla e riavvia la coroutine ogni volta che il Lifecycle raggiunge lo stato specificato.

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

La coroutine passata a repeatOnLifecycle si avvia quando il Lifecycle raggiunge STARTED e viene annullata quando scende al di sotto di STARTED. Al ritorno a STARTED, la coroutine si riavvia da capo. Questo è sicuro ed efficiente — nessuna coroutine rimane in sospeso.

flowWithLifecycle — Per Flow

Per raccogliere dati da Flow con consapevolezza del ciclo di vita, esiste l’operatore flowWithLifecycle. Arresta e riprende automaticamente la raccolta quando lo stato del Lifecycle cambia:

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

L’operatore flowWithLifecycle è il modo più conciso per abbonarsi in sicurezza a un Flow nel livello UI.

Esempi di utilizzo di lifecycleScope

Esaminiamo tre scenari reali di utilizzo di lifecycleScope in un’applicazione Android con Kotlin.

Esempio 1: Iscriversi agli aggiornamenti di posizione solo quando lo schermo è visibile

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

La coroutine si avvia quando il fragment diventa visibile (STARTED) e viene annullata quando esce dallo schermo (STOPPED). Se l’utente passa a un’altra applicazione, gli aggiornamenti di posizione non consumano batteria.

Esempio 2: Avviare un’animazione all’avvio del fragment

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

L’animazione viene eseguita solo quando il fragment è in primo piano (RESUMED). Se l’utente minimizza l’app durante l’animazione, la coroutine viene annullata e, al ritorno, l’animazione si riavvia.

Esempio 3: Sincronizzazione periodica dei dati su uno schermo visibile

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

I dati vengono sincronizzati ogni 30 secondi, ma solo quando lo schermo è visibile. isActive verifica se la coroutine è stata annullata, fornendo un’uscita sicura dal ciclo quando si lascia lo schermo.

lifecycleScope vs viewModelScope: scenari d’uso

Entrambi gli scope sono legati al ciclo di vita, ma a diversi aspetti di esso. Comprendere la differenza è fondamentale per un’architettura corretta delle applicazioni Android.

Differenza chiave

viewModelScope è legato al ViewModel, che sopravvive alla rotazione dello schermo. lifecycleScope è legato al LifecycleOwner (Activity/Fragment), che viene distrutto e ricreato durante la rotazione. Questo determina i loro scenari d’uso.

Quando usare lifecycleScope

  • Iscriversi agli eventi di sistema (posizione, sensori, fotocamera)
  • Animazioni ed effetti UI legati a uno schermo specifico
  • Caricamento di dati a blocchi in base alla visibilità dello schermo
  • Operazioni che dovrebbero fermarsi quando si lascia lo schermo

Quando usare viewModelScope

  • Caricamento dati da un Repository
  • Logica di business che deve sopravvivere alla rotazione
  • Caching ed elaborazione dei dati
  • Qualsiasi operazione il cui risultato è necessario dopo la rotazione

Utilizzo combinato

In pratica, è comune una combinazione di entrambi gli scope: viewModelScope carica i dati e gestisce lo stato, mentre lifecycleScope si iscrive al Flow dal ViewModel con consapevolezza del ciclo di vita. Questa separazione delle responsabilità è considerata una best practice nello sviluppo Android moderno.

Errori comuni con lifecycleScope

Esaminiamo quattro degli errori più comuni commessi dagli sviluppatori nell’utilizzo di lifecycleScope.

Errore 1: Usare lifecycleScope invece di viewModelScope per caricare dati

Se si avvia il caricamento dati in lifecycleScope.launch, la coroutine verrà annullata durante la rotazione dello schermo e i dati dovranno essere ricaricati. Usa viewModelScope per le operazioni a lunga durata. lifecycleScope è solo per le attività legate all’UI.

Errore 2: Raccogliere Flow senza repeatOnLifecycle

Chiamare direttamente viewModel.someFlow.collect { ... } all’interno di lifecycleScope.launch continua a raccogliere dati anche quando lo schermo non è visibile. Ciò può portare ad aggiornamenti dell’UI in background e un sovraccarico inutile. Usa sempre repeatOnLifecycle o flowWithLifecycle.

Errore 3: Dimenticare la cancellazione quando si lascia lo schermo

Sebbene lifecycleScope venga annullato a DESTROYED, il codice dopo un punto di sospensione potrebbe non essere eseguito in caso di annullamento improvviso. Non fare affidamento sull’esecuzione del codice dopo una chiamata suspend, a meno che tu non stia usando NonCancellable.

Errore 4: Usare il deprecato launchWhenStarted invece di repeatOnLifecycle

launchWhenStarted e i suoi equivalenti non annullano la coroutine, la mettono solo in pausa. Se lo schermo passa tra primo piano e sfondo più volte, la coroutine accumula chiamate differite. Passa a repeatOnLifecycle — questo è l’unico modo corretto per sincronizzarsi con il Lifecycle.

Domande frequenti

Qual è la differenza tra lifecycleScope e GlobalScope?

lifecycleScope viene automaticamente annullato quando il LifecycleOwner viene distrutto. GlobalScope vive per tutta la durata dell’applicazione. Una coroutine in lifecycleScope non può aggiornare l’UI dopo la distruzione del componente, mentre in GlobalScope può farlo, causando crash. Usa sempre lifecycleScope nel livello UI.

Si può usare lifecycleScope in un ViewModel?

No, ViewModel non è un LifecycleOwner, quindi lifecycleScope non è disponibile al suo interno. ViewModel usa viewModelScope. Se il codice deve essere eseguito in entrambi i contesti, estrai la logica in un use case o repository con funzioni suspend.

Cosa succede quando repeatOnLifecycle viene chiamato più volte?

Ogni chiamata a repeatOnLifecycle crea una nuova coroutine che esegue il blocco quando viene raggiunto lo stato specificato del Lifecycle. Se repeatOnLifecycle viene chiamato due volte per lo stesso stato, entrambi i blocchi verranno eseguiti indipendentemente. Di solito, una singola chiamata in onViewCreated è sufficiente.

Si può impostare un Dispatcher personalizzato per lifecycleScope?

Non è possibile modificare direttamente il dispatcher di lifecycleScope — usa Dispatchers.Main.immediate. All’interno del blocco della coroutine, puoi passare a un altro dispatcher tramite withContext. Per i test, usa TestDispatcher con LifecycleOwner.

lifecycleScope viene annullato in onPause o onDestroy?

lifecycleScope viene annullato quando il LifecycleOwner passa allo stato DESTROYED (dopo onDestroy). Le semplici chiamate a lifecycleScope.launch non vengono annullate in onPause o onStop. Per mettere in pausa quando si passa in background, usa repeatOnLifecycle(STARTED) o repeatOnLifecycle(RESUMED).

Riepilogo

  • lifecycleScope — CoroutineScope legato a un LifecycleOwner e automaticamente annullato a DESTROYED tramite LifecycleEventObserver
  • Dispatchers.Main.immediate — il dispatcher predefinito, che garantisce aggiornamenti sicuri dell’UI senza cambi superflui
  • repeatOnLifecycle — API moderna per avviare coroutine a uno stato specifico del Lifecycle con annullamento e riavvio automatici
  • flowWithLifecycle — operatore per la raccolta sicura di Flow dall’UI con consapevolezza del ciclo di vita
  • launchWhenStarted deprecato — invece di mettere in pausa, usa repeatOnLifecycle che annulla la coroutine anziché metterla in pausa
  • lifecycleScope vs viewModelScope — lifecycleScope per operazioni UI (animazioni, posizione), viewModelScope per dati e logica di business
  • Rotazione dello schermo — lifecycleScope viene annullato durante la rotazione, viewModelScope sopravvive; scegli lo scope in base al compito

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche