Componenti di architettura Android Lifecycle e LiveModel

Nell'ultima parte di questa serie, Introduzione ai componenti di architettura Android, abbiamo parlato della nuova architettura Android e del perché è stata sviluppata. Fondamentalmente, la nuova architettura affronta alcuni problemi noti di Android offrendo un pacchetto di componenti su misura per il sistema. Questi sono gli elementi costitutivi dell'architettura. Abbiamo già dato una rapida occhiata a questi componenti, quindi ora è il momento di iniziare a immergerci in essi. 

In questo tutorial, daremo un'occhiata da vicino al Ciclo vitale e il LiveModel componenti. Mentre li esploriamo, esamineremo anche alcuni frammenti di codice da un'applicazione di esempio. Dato che stiamo parlando dei nuovi paradigmi di Android, i frammenti sono tutti realizzati con il fantastico Kotlin.

Se non conosci ancora Kotlin, per favore non aver paura di seguirlo; l'implementazione è estremamente vicina a Java e sono sicuro che sarete in grado di capirlo. Se vuoi saperne di più su Kotlin, Jessica Thornsby ha scritto una serie eccellente qui su Tuts + sulle app Android di codifica in Kotlin. Dovresti dare un'occhiata!

  • Codifica delle app Android funzionali in Kotlin: come iniziare

    Hai sentito cose positive sul linguaggio Kotlin per le app Android e vuoi provarlo tu stesso? Scopri come impostare e avviare la codifica in questo nuovo ...
    Jessica Thornsby
    Studio Android
  • Codifica delle app Android funzionali in Kotlin: Lambdas, Null Safety & More

    Il linguaggio Kotlin per le app per Android ti consente di fare una codifica che potrebbe essere molto più prolissa in Java o impossibile da ottenere con Java da solo. Impara come…
    Jessica Thornsby
    SDK Android

1. Il progetto di esempio

Abbiamo fornito una piccola applicazione dimostrando i concetti di cui stiamo parlando in questo tutorial. Il nome dell'app è MyWeatherApp e consente all'utente di recuperare il tempo del giorno utilizzando il nome di una città o la posizione corrente dell'utente. La logica dell'app è abbastanza semplice, ma potresti migliorarla per creare la tua applicazione.

Come potete vedere nel diagramma sottostante, l'architettura è conforme a quella proposta da Android, e abbiamo usato il nuovo pacchetto Architecture Components il più possibile, mantenendo le cose abbastanza semplici per un'analisi di base. Come bonus, stiamo usando Dagger 2 come libreria di Dependency Injection. Tuttavia, non approfondiremo molti dettagli sulla sua implementazione, dal momento che sfuggirebbe allo scopo del tutorial.

Come funziona l'app?

L'applicazione è il più semplice possibile. Ha solo un'attività, in cui l'utente può ottenere il meteo cercando il nome di una città o utilizzando la posizione corrente del dispositivo. Il Attività principale chiama il MainModel per ottenere un osservabile LiveData e reagisce ad esso. Il MainModel recupera i dati meteorologici dal MainRepository, e consolida tutti i dati come LiveData. Il MainRepository ottiene i suoi dati da più fonti.

Esecuzione dell'applicazione di esempio

Scarica o clona il repository dal nostro repository GitHub e crea con Gradle o aprilo nel tuo IDE. È inoltre necessario creare un account OpenWeatherMap e ottenere un nuovo ID applicazione. Aggiungi l'ID applicazione su una risorsa stringa chiamata openWeather.

XXXXXXXXXXXXXXX

2. Impostazione di un progetto

Poiché i componenti di architettura sono ancora in alfa, devi includere il repository di Google, che contiene alcune librerie sperimentali, nelle build.gradle.

allprojects repository // aggiungi questo repository maven url 'https://maven.google.com'

Nel modulo build.gradle, aggiungi quanto segue al dipendenze sezione per aggiungere il supporto per Cicli vitaliLiveData, e ViewModel:

  • compila "android.arch.lifecycle: runtime: 1.0.0-alpha5"
  • compila "android.arch.lifecycle: extensions: 1.0.0-alpha5"
  • annotationProcessor "android.arch.lifecycle: compiler: 1.0.0-alpha5"

Se stai usando Kotlin, devi anche aggiungere o sostituire il annotationProcessor con Kapt, che gestisce le annotazioni su Kotlin.

kapt "android.arch.lifecycle: compiler: 1.0.0-alpha5"

Abilitare Kapt, aggiungi quanto segue nel modulo build.gradle radice.

kapt generateStubs = true

3. Il Ciclo vitale Componente

Ogni sviluppatore Android ha familiarità con il concetto del ciclo di vita. Il sistema guida il ciclo di vita di applicazioni, attività, frammenti e così via, senza il controllo dello sviluppatore. Questo concetto è uno dei paradigmi di Android e, fino a poco tempo fa, non era così facile da lavorare, dal momento che non era possibile controllare direttamente lo stato del ciclo di vita di un componente. Quello che potevamo fare era reagire a determinati metodi, come onCreateOnDestroy, innescato da eventi del ciclo di vita.

Tutto ciò è cambiato dall'annuncio del pacchetto Architecture Components, che ha introdotto un componente chiamato Ciclo vitale. Ora, alcuni oggetti Android hanno un Ciclo vitale collegato a loro, e questo cambia molte cose per gli sviluppatori. È possibile consultare a Ciclo vitale stato in un dato momento, ed è anche possibile reagire a Ciclo vitale eventi usando annotazioni. In realtà, la spina dorsale del nuovo Android Architecture Components è il Ciclo vitale componente.

Tutti gli elementi del pacchetto android.arch.lifecycle sono importanti per il ciclo vitale concetto, ma due di essi meritano più attenzione: LifecycleOwnerLifecycleObserver. Creano la possibilità di lavorare con Ciclo vitale, osservare e reagire agli eventi che si verificano su attività, frammenti, servizi e così via.

Il LifecycleOwner

Il LifecycleOwner è un'interfaccia a metodo singolo per classi che contengono a Ciclo vitale. Estrae il possesso di a Ciclo vitale, ti consente di scrivere componenti che possono funzionare con esso. Secondo i nuovi standard, le attività e i frammenti sono LifecycleOwnerS. Tuttavia, fino all'avvio della versione finale di Architecture Components, è necessario utilizzare alcune classi speciali: ActivityLifecycleFragmentLifecycle, e LifecycleService.

class MainActivity: LifecycleActivity () override fun onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState)

Non vi è alcun cambiamento significativo nell'implementazione di queste classi rispetto alle attività e ai frammenti standard. Una volta che una classe estende qualcuno di loro, avrà a Ciclo vitale allegato, che può essere recuperato in qualsiasi momento con il metodo getLifecycle (). Un'altra possibilità interessante è che possiamo controllare lo stato attuale del ciclo di vita con getCurrentState, che restituisce a Lifecycle.State

Ce ne sono cinque diversi Ciclo vitale stati:

  • INITIALIZED: per un oggetto che è stato chiamato, ma che non è ancora "attivo". È l'equivalente di uno stato prima del Activity.onCreate metodo.
  • CREATO: per oggetti che sono stati appena creati. Si chiama dopo il onCreate metodo e anche chiamato poco prima del onStop metodo.
  • INIZIATO: chiamato dopo il onStart e poco prima del onPause metodo.
  • RIPRESO: Lo stato attivo o lo stato ripristinato per a LifecycleOwner. Chiamato dopo onResume metodo.
  • DISTRUTTO: per un distrutto LifecycleOwner oggetto. Questo Ciclo vitale non invierà più eventi. Questo evento è raggiunto subito prima del OnDestroy metodo.

Il LifecycleObserver

Una delle proprietà più interessanti del Ciclo vitale è che può essere facilmente osservato.  LifecycleObserver le classi possono osservare LifecycleOwner componenti, come attività e frammenti. Riceve LifecycleOwner.Events, e può reagire a loro attraverso l'annotazione @OnLifeCycleEvent (Lifecycle.Event).

class MainObserver: LifecycleObserver, AnkoLogger @OnLifecycleEvent (Lifecycle.Event.ON_RESUME) fun onResult () info ("onResult") @OnLifecycleEvent (Lifecycle.Event.ON_STOP) fun onStop () info ("onStop")

I metodi annotati con @OnLifecycleEvent non ho bisogno di argomenti, ma se usato, il primo argomento deve essere il LifecycleOwner. Quando utilizza l'annotazione Lifecycle.Event.ON_ANY, il metodo dovrebbe aspettarsi due argomenti: LifecycleOwner e Lifecycle.Event.

@OnLifecycleEvent (Lifecycle.Event.ON_ANY) fun onEvent (proprietario: LifecycleOwner, event: Lifecycle.Event) info ("onEvent: ownerState: $ owner.lifecycle.currentState") informazioni ("onEvent: event: $ event" )

Per attivare il @OnLifecycleEvent annotazione, il LifecycleObserver deve essere osservando a Ciclo vitale, altrimenti non riceverà l'evento. Per far funzionare questo, chiama Lifecycle.addObserver (LifecycleOwner) e il LifecycleOwner sarà successivamente in grado di reagire a Lifecycle.Event. È anche possibile chiamare Lifecycle.removeObsever (LifecycleObserver) rimuovere un osservatore.

class MainActivity: LifecycleActivity (), AnkoLogger @Inject lateinit var mainObserver: MainObserver sovrascrive fun onCreate (savedInstanceState: Bundle?) // ... // Su Kotlin, invece di getLifecycle, // possiamo chiamare direttamente il ciclo di vita lifecycle.addObserver (mainObserver ) override fun onDestroy () // ... lifecycle.removeObserver (mainObserver)

Ci sono vari casi d'uso interessanti per LifecycleObserver. Ad esempio, potrebbe essere utilizzato per creare un Presentatore livello dal modello di architettura Model View Presenter. Potrebbe anche essere usato per creare ascoltatori che possono smettere di ascoltare quando il Ciclo vitale è disabilitato.

4. Il LiveModel Componente

Progettato per funzionare insieme allo strato UI, il ViewModel componente chiude una lacuna che è esistita in Android sin dall'inizio: fornire un modo per gestire e archiviare elegantemente gli oggetti dati relativi alla vista. Il componente mantiene l'integrità dei dati tra le modifiche alla configurazione, può essere condiviso tra Attività e Frammenti ed è uno strumento eccellente per evitare completamente perdite di memoria.

Il ViewModel viene sempre creato in stretta relazione con un ambito specifico, sia un'attività che un frammento. L'ambito viene mantenuto finché l'attività o il frammento sono vivi. In termini pratici, il ViewModel ricollega la vista dopo le modifiche alla configurazione, mantenendo se stessa fino a quando la vista principale non viene distrutta. Secondo la documentazione ufficiale:

Lo scopo del ViewModel è acquisire e conservare le informazioni necessarie per un'attività o un frammento.

Oltre a tutto ciò, il ViewModel facilita la separazione delle preoccupazioni nel processo di sviluppo di Android. Spostando tutte le operazioni relative ai dati a questo componente e lasciandolo gestire la logica, la testabilità e la manutenibilità dell'applicazione sono notevolmente aumentate. Con ViewModel, è possibile adottare facilmente l'architettura Android proposta nel Google I / O 2017. Puoi persino usarlo per adottare modelli di architettura più sofisticati, come MVP o MVVM.

Implementazione a ViewModel

Esistono due modi per implementare a ViewModel. Quello standard è di estendere la classe, fornendo un costruttore senza argomenti. Questo è il modo più semplice, ma non funziona bene con Dependency Injection.

class MainViewModel: ViewModel () init // initialize some behavior fun getData (): LiveData // get some data override fun onCleared () super.onCleared () // chiamato prima della sua distruzione

Prendere un ViewModel costruito con questa tecnica da un'attività o da un frammento, basta chiamare ViewModelProviders.of (FragmentActivity) .get (Classe). L'ultimo argomento deve contenere il ViewModel classe. Lo stesso ViewModel l'istanza verrà recuperata dalla vista e conterrà tutti i dati per quella vista.

val viewModel: MainViewModel = ViewModelProviders.of (this) .get (MyViewModel :: class.java)

Si noti che, dal momento che il ViewModel è preso da ViewModelProviders.of metodo, il suo costruttore non può ricevere argomenti. Come soluzione alternativa, è possibile implementare a ViewModelProvider.Factory. In realtà, questa è la stessa tecnica che usiamo per iniettare ViewModel.

Iniezione a ViewModel

Quando si usa DI, le cose diventano un po 'più complicate. Dovrai implementare a ViewModelProvider.Factory. I seguenti passaggi possono essere utilizzati per iniettare a ViewModel usando Dagger. Il ViewModelFactory è una classe di utilità che fornisce a ViewModel per uno scopo.

@Suppress ("UNCHECKED_CAST") @Singleton class ViewModelFactory @Inject constructor (private val creator: Map, @JvmSuppressWildcards Provider>): ViewModelProvider.Factory override fun  create (modelClass: Class): T var creator: Provider? = creatori [modelClass] if (creatore == null) for ((chiave, valore) nei creatori) if (modelClass.isAssignableFrom (chiave)) creator = value break if (creatore == null) throw IllegalArgumentException ("classe del modello sconosciuta" + modelClass) prova return creator.get () come T catch (e: Exception) throw RuntimeException (e)

Anche il pugnale ha bisogno di a @MapKey definito per ViewModel e un legante per ogni modello e per la fabbrica nel modulo.

// @MapKey @MustBeDocumented @Target (AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) @ kotlin.annotation.Retention () @MapKey classe di annotazione interna ViewModelKey (valore val: KClass) // ViewModel Module @Module abstract class ViewModelsModule // Collega ogni ViewModel @Binds @IntoMap @ViewModelKey (MainViewModel :: class) abstract fun bindMainViewModel (mainViewModel: MainViewModel): ViewModel // ViewModel factory binding @Binds abstract fun bindViewModelFactory (factory : ViewModelFactory): ViewModelProvider.Factory

Successivamente, segui le procedure standard di Dagger e sarai in grado di crearne uno ViewModel capace di iniettare argomenti sul suo costruttore. Per creare una nuova istanza, prendi il ViewModelFactory e prendi il desiderato ViewModel da.

// Ottieni ViewModel factory @Inject lateinit var viewModelFactory: ViewModelProvider.Factory // Visualizza ViewModel val viewModel = ViewModelProviders.of (this, viewModelFactory) .get (MainViewModel :: class.java)

Nel nostro progetto di esempio, puoi dare un'occhiata a DI con Dagger. Ti ho anche fornito una cartella di esempi nel tutorial Repository GitHub con frammenti che mostrano come configurare ViewModels sul sistema di Dagger usando Kotlin.

class MainViewModel @Inject constructor (private val repository: MainRepository): ViewModel (), AnkoLogger // ... codice qui va

Conclusione

Finora, il nostro viaggio attraverso i nuovi componenti di Android Architecture è stato molto produttivo. Tuttavia, abbiamo ancora un terreno da percorrere. Nel prossimo tutorial parleremo del fantastico LiveData componente, indagando le sue funzionalità di base e avanzate e applicando questi concetti alla nostra applicazione di esempio.

A presto! E nel frattempo, dai uno sguardo ad alcuni dei nostri altri post sullo sviluppo di app per Android!