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!
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.
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.
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
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 vitali
, LiveData
, 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
Ciclo vitale
ComponenteOgni 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 onCreate
e OnDestroy
, 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: LifecycleOwner
e LifecycleObserver
. Creano la possibilità di lavorare con Ciclo vitale
, osservare e reagire agli eventi che si verificano su attività, frammenti, servizi e così via.
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 LifecycleOwner
S. Tuttavia, fino all'avvio della versione finale di Architecture Components, è necessario utilizzare alcune classi speciali: ActivityLifecycle
, FragmentLifecycle
, 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.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.Event
s, 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.
LiveModel
ComponenteProgettato 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.
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
.
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
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!