Sviluppando per Android, sappiamo che la gestione del ciclo di vita ha un'importanza fondamentale per il programmatore. La dinamicità con cui l'utente passa da un'applicazione all'altra o eventi inaspettati come l'arrivo di una telefonata, fanno mutare lo stato dell'app ed interferiscono col suo ciclo di vita. Ciò generalmente innesca comportamenti interni come l'attivazione o disattivazione di servizi, salvataggio o caricamento dello stato.
La gestione tradizionale del ciclo di vita è sempre consistita nell'implementazione di appositi metodi di callback, ognuno dei quali viene invocato in automatico dal sistema all'ingresso in un nuovo stato. Tale metodologia si è sempre rivelata efficace ma nonostante ciò potrebbe celare insidie in qualche caso. Per questo motivo, nella libreria Android Architecture Components è stato introdotto un package dedicato alla gestione del ciclo di vita, denominato android.arch.lifecycle: esso sarà l'oggetto di questa lezione.
Integrazione del package
Il package può essere integrato in un progetto seguendo due passaggi:
- aggiungiamo il repository Maven nel file build.gradle di livello progetto:
allprojects {repositories { jcenter() maven { url 'https://maven.google.com' } } }
- inseriamo la dipendenza nel modulo applicativo:
dependencies { ... ... compile 'android.arch.lifecycle:runtime:1.0.3' }
Dopo la sincronizzazione del progetto con i file di Gradle, avremo la libreria a nostra disposizione.
Struttura del package
All'interno del package troviamo alcuni elementi di interesse, ognuno dei quali gestisce problematiche differenti. Vediamone i principali:
- LifecycleObserver è un'interfaccia che non prevede metodi ma serve solo per etichettare una classe in cui
verrà usata l'annotazione@OnLifecycleEvent
. Da questa interfaccia ne deriva per ereditarietà un'altra,DefaultLifecycleObserver
, che contiene sei metodi di default, ognuno per un diverso cambio di stato del ciclo di vita:onCreate
,onResume
,onStart
,onPause
,onStop
,onDestroy
. L'interfaccia DefaultLifecycleObserver è consigliata quando si usa la sintassi di Java 8, in alterntiva alla prassi delle annotazioni; - @OnLifecycleEvent è un annotation Java a singolo valore che serve ad introdurre il metodo del
LifecycleObserver
che gestisce un determinato evento del ciclo di vita; - LifecycleRegistry è una classe che gestisce più
LifecycleObserver
per seguire il ciclo di vita. Viene istanziato tramite un costruttore che riceve come unico argomento un riferimento alLifecycleOwner
, la classe che possiede il ciclo di vita (ad esempio, l'Activity). Tra i suoi metodi principali particolarmente utili, vi sono:addObserver
che aggiunge unLifecycleObserver
;removeObserver
che rimuove unLifecycleObserver
;markState
che segna il passaggio ad un'altra fase del ciclo di vita e lo notifica agli observer registrati.
Impostazione dell'app
Per impostare un'applicazione in modo che sfrutti questi strumenti, possiamo seguire in linea di massima i seguenti passi.
Creiamo una classe che interpreti il ruolo di LifecycleObserver e predisponiamo al suo interno il codice necessario per gestire i vari stati. Supponendo di usare la modalità con LifecycleObserver
e annotazioni @LifecycleEvent
, possiamo procedere così:
class StatoApp implements LifecycleObserver {
private boolean enabled;
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void start() {
if (enabled) {
// codice da eseguire in onStart
}
}
public void enable() {
enabled = true;
// altro codice per abilitazione della classe
}
}
Come si vede, non abbiamo fatto altro che predisporre un metodo ed etichettarlo con l'annotazione (in questo caso, per lo stato
Started). Ciò andrebbe ripetuto poi per tutti i vari stati da gestire. Si noti che abbiamo inserito anche un metodo enable()
che serve ad abilitare l'observer; viceversa, un observer non abilitato non sortirebbe alcun effetto. Un metodo del genere non è
indispensabile ma può essere utile per mettere in funzione o disabilitare un observer ancora collegato.
Per fare in modo che l'observer venga invocato al momento opportuno, dobbiamo mettere in condizione il nostro oggetto (ad esempio, l'Activity) di avvisare subito gli observer:
public class MainActivity extends AppCompatActivity implements LifecycleOwner {
// 1. fissiamo la variabile d'istanza registry
private LifecycleRegistry registry;
// questo metodo è richiesto da LifecycleOwner.
// gli facciamo restituire il registry
@NonNull
@Override
public Lifecycle getLifecycle() {
return registry;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 3. inizializza il registry
registry = new LifecycleRegistry(this);
//4. assegniamo observer
registry.addObserver(new StatoApp());
// 5. segniamo lo stato CREATED
registry.markState(Lifecycle.State.CREATED);
}
@Override
protected void onStart() {
super.onStart();
registry.markState(Lifecycle.State.STARTED);
}
}
Nonostante il codice non faccia niente di operativo, si noti come sono stati legati i nuovi elementi all'Activity. Per prima
cosa abbiamo definito una variabile d'istanza di tipo LifecycleRegistry
. Questa gestirà gli observer e li attiverà al momento
opportuno. Il LifecycleRegistry
è stato inizializzato nel metodo onCreate
, e sempre in questo metodo vede l'assegnazione dell'observer con l'invocazione di addObserver
. Ogni volta che lo stato del ciclo di vita cambia è importante notificarlo al registry con il metodo markState()
, che di conseguenza informa i vari observer collegati. Nella struttura dell'esempio, come si vede, markState()
è stato invocato due volte: una volta nel metodo onCreate
ed una volta in onStart
.
A questo punto non manca altro che definire una strategia di gestione degli eventi del ciclo di vita in base agli scopi della propria applicazione. Quanto abbiamo visto si innesta nella struttura proposta dalle Android Architecture Components, i cui ulteriori elementi ed applicazioni saranno discussi nelle prossime lezioni.