Android e l'Architettura
Il sistema operativo Android fornisce una solida base per creare app che funzionano bene su una vasta gamma di dispositivi e fattori di forma. Premesso ciò, abbiamo ascoltato i feedback degli sviluppatori sulle questioni come i cicli di vita complessi e la mancanza di un'architettura delle app consigliata, che rendono difficile la scrittura di app robuste.
Dobbiamo rendere più semplice e più divertente la scrittura di app robuste che consentano agli sviluppatori di concentrarsi su aree in cui possono essere innovativi. Oggi presentiamo una guida all'architettura di app Android insieme all'anteprima di Architecture Components. Anziché reinventare la ruota, vogliamo sfruttare i risultati già ottenuti dalle librerie Android più popolari.
Pareri, non prescrizioni
Sappiamo che ci sono più modi di scrivere app Android. Ciò che forniamo è un insieme di linee guida che possono aiutarti a progettare app Android che funzionino meglio nell'ambito delle particolari modalità d'interazione di Android. Il framework di Android dispone di API ben definite per gestire i punti di contatto con il sistema operativo, ad esempio le Attività, ma queste sono punti di ingresso nella tua app, non i blocchi predefiniti per l'architettura dell'app. I componenti del framework non ti costringono a separare il modello di dati dai componenti dell'UI o a fornire un modo chiaro per rendere permanenti i dati indipendentemente dal ciclo di vita.
Blocchi predefiniti
Gli Architecture Components di Android lavorano insieme al fine di implementare un'architettura sana e al tempo stesso risolvono individualmente i punti critici che deve affrontare uno sviluppatore. Il primo set di questi componenti consente di:
- Gestire automaticamente la tua attività e i cicli di vita dei frammenti per evitare perdite di memoria e risorse
- Rendere permanenti gli oggetti di dati Java in un database SQLite
I nuovi componenti compatibili con il ciclo di vita forniscono i costrutti per collegare i componenti principali delle app a eventi di ciclo di vita, eliminando così i percorsi di dipendenza esplicita.
Un tipico modello di osservazione Android consiste nell'avviare l'osservazione in
onStart() e interromperla in
onStop(). Sembra abbastanza semplice, ma a volte diverse chiamate asincrone si verificano contemporaneamente gestendo ciascuna i cicli di vita del proprio componente. È facile non accorgersi di un caso limite. I componenti del ciclo di vita possono essere utili.
La classe principale è
Lifecycle. Utilizza un'enumerazione per l'
attuale stato del ciclo di vita parallelamente a una enumerazione per gli eventi di ciclo di vita in modo da monitorare lo stato del ciclo di vita del componente associato.
Stati ed eventi del ciclo di vita
LifecycleOwner è un'interfaccia che restituisce un oggetto Lifecycle dal metodo
getLifecycle(), mentre
LifecycleObserver è una classe che può monitorare gli eventi del ciclo di vita del componente aggiungendo annotazioni ai suoi metodi. Mettendo tutto insieme, siamo in grado di creare componenti compatibili con il ciclo di vita che possono sia monitorarne gli eventi sia eseguire query sullo stato attuale del ciclo di vita.
public class MyObserver implements LifecycleObserver {
public MyObserver(Lifecycle lifecycle) {
// Starts lifecycle observation
lifecycle.addObserver(this);
...
}
public void startFragmentTransaction() {
// Queries lifecycle state
if (lifecycle.getState.isAtLeast(STARTED)) {
// perform transaction
}
}
// Annotated methods called when the associated lifecycle goes through these events
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
}
}
MyObserver observer = new MyObserver(aLifecycleOwner.getLifecycle());
LiveData è una classe osservabile di data holder compatibile con il ciclo di vita. Il tuo codice UI sottoscrive le modifiche dei dati sottostanti, legati a
LifecycleOwner, mentre
LiveData si assicura che l'observer:
- Ottenga gli aggiornamenti dei dati mentre Lifecycle è in uno stato attivo (STARTED o RESUMED)
- Sia rimosso quando LifecycleOwner viene distrutto
- Venga aggiornato quando LifecycleOwner si riavvia a causa di una modifica alla configurazione o viene riavviato dal back stack
Ciò consente di eliminare molti percorsi per perdite di memoria e riduce gli arresti anomali evitando gli aggiornamenti di attività interrotte.
LiveData può essere osservato da molti listener, ognuno legato a un proprietario del ciclo di vita, come un frammento o un'attività.
ViewModel è una classe helper che contiene dati UI per un frammento o un'attività, che serve a separare la proprietà dei dati in visualizzazione dalla logica del controller UI. Un ViewModel viene mantenuto finché l'ambito dell'attività o del frammento è attivo, anche quando l'attività/il frammento viene distrutto e ricreato a causa di una modifica della configurazione, che consente a ViewModel di rendere disponibili i dati UI all'attività ricreata o all'istanza di frammento. La disposizione di dati UI archiviati all'interno del ViewModel con LiveData fornisce ai dati una dimora osservabile compatibile con il ciclo di vita. LiveData gestisce il lato delle notifiche mentre ViewModel si assicura che i dati siano correttamente conservati.
Gli Architecture Components di Android semplificano anche la persistenza dei dati nell'ambito della libreria
Room. Room fornisce un livello di astrazione per il mapping degli oggetti che consente un accesso fluido al database, sfruttando al tempo stesso tutta la potenza di SQLite. Il framework principale offre un supporto integrato per operare con i contenuti SQL raw. Nonostante queste API siano potenti, il loro livello è abbastanza basso e richiedono una grande quantità di tempo e sforzo se:
- Non esiste alcuna verifica per il tempo di compilazione delle query SQL inattive.
- Lo schema cambia, dovrai aggiornare manualmente le query SQL in questione. Questo processo può richiedere molto tempo ed è soggetto a errori.
- Dovrai scrivere parecchio codice boilerplate per convertire le query SQL in oggetti di dati Java.
Room ti risolve il problema mettendoti a disposizione un livello di astrazione su SQLite.
Sono presenti tre componenti principali in Room:
- Entità rappresenta i dati per una singola riga di database, compilati con un oggetto di dati Java annotato. Ogni Entità viene resa permanente nella sua tabella.
- DAO (Data Access Object) definisce i metodi che accedono al database utilizzando le annotazioni per associare SQL a ciascun metodo.
- Database è una classe holder che utilizza le annotazioni per definire l'elenco di entità e la versione del database. Il contenuto della classe definisce l'elenco di DAO. È anche il punto di accesso principale per la connessione al database sottostante.
Per utilizzare Room, devi annotare gli oggetti di dati Java che desideri rendere permanenti come entità, creare un database contenente queste entità e definire una classe DAO con SQL per accedere e modificare il database.
@Entity
public class User {
@PrimaryKey
private int uid;
private String name;
// Getters and Setters - required for Room
public int getUid() { return uid; }
public String getName() { return name; }
public void setUid(int uid) { this.uid = uid; }
public void setName(String name) { this.name = name; }
}
@Dao
public interface UserDao {
@Query("SELECT * FROM user")
List getAll();
@Insert
void insertAll(User... users);
}
@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
Gli Architecture Components sono progettati per essere autonomi, ma sono più efficaci se incorporati nell'architettura efficace di un'app. Oggi lanciamo la
Guida all'architettura dell'app che illustra come creare un'app robusta, modulare e testabile utilizzando gli Architecture Components. La guida ha tre obiettivi principali:
- Definire i principi applicabili allo sviluppo di app Android
- Descrivere un'architettura di app che funzioni con questi principi
- Mostrare come implementare tale architettura utilizzando gli Architecture Components
Consigliamo a tutti gli sviluppatori che hanno dovuto occuparsi di questi problemi di leggere la Guida. Anche se sei soddisfatto dell’attuale architettura della tua app, la Guida ti offrirà spunti e approfondimenti utili.
È solo l'inizio
Vogliamo continuare a essere un po' polemici e continuare a introdurre nuovi Architecture Components per facilitare gli sviluppatori Android a prendere decisioni informate nell'ambito dell'architettura delle loro app. Ti invitiamo a provare l'anteprima e a fornirci i tuoi commenti, perché in fondo abbiamo tutti lo stesso obiettivo: rendere più semplice e divertente lo sviluppo di app Android. Per ulteriori informazioni sull'architettura di Android, consulta: