In het laatste deel van deze serie, Introduction to Android Architecture Components, hebben we het gehad over de nieuwe Android-architectuur en waarom deze is ontwikkeld. Kort gezegd, de nieuwe architectuur lost een aantal bekende Android-problemen op door een bundel componenten op maat voor het systeem aan te bieden. Dit zijn de bouwstenen van de architectuur. We hebben deze componenten al snel bekeken, dus nu is het tijd om er diep in te duiken.
In deze zelfstudie zullen we de Levenscyclus
en de LiveModel
componenten. Terwijl we deze onderzoeken, gaan we ook enkele codefragmenten bekijken in een voorbeeldtoepassing. Omdat we het hebben over de nieuwe paradigma's van Android, zijn de fragmenten allemaal gemaakt met de geweldige Kotlin.
Als je Kotlin nog niet kent, wees alsjeblieft niet bang om mee te gaan; de implementatie ligt heel dicht bij Java en ik ben ervan overtuigd dat je het zult begrijpen. Als je meer wilt weten over Kotlin, schreef Jessica Thornsby hier een uitstekende serie over Tuts + over het coderen van Android-apps in Kotlin. Je zou eens moeten kijken!
We hebben een kleine applicatie verstrekt waarmee we de concepten laten zien waar we het over hebben in deze tutorial. De naam van de app is MyWeatherApp en de gebruiker kan het weer van de dag ophalen met de naam van een stad of de huidige locatie van de gebruiker. De logica van de app is vrij eenvoudig, maar u kunt deze verbeteren om uw eigen toepassing te maken.
Zoals u in het onderstaande diagram kunt zien, voldoet de architectuur aan die van Android en hebben we het nieuwe pakket Architectuurcomponenten zoveel mogelijk gebruikt, zodat de dingen eenvoudig genoeg zijn voor een basisanalyse. Als een bonus gebruiken we Dagger 2 als een bibliotheek voor afhankelijkheidsinjectie. We zullen echter niet in detail ingaan op de implementatie ervan, omdat dit zou ontsnappen aan de scope van de tutorial.
De applicatie is zo eenvoudig mogelijk. Het heeft slechts één activiteit, waarbij de gebruiker het weer kan krijgen door de naam van een stad te doorzoeken of de huidige locatie van het apparaat te gebruiken. De Hoofdactiviteit
roept de MainModel
om een waarneembaar te krijgen Actuele gegevens
en reageert erop. De MainModel
haalt weergegevens van de MainRepository
, en consolideert alle gegevens als Actuele gegevens
. De MainRepository
haalt zijn gegevens uit meerdere bronnen.
Download of clone de repository uit onze GitHub repo en bouw met Gradle of open het in je IDE. U moet ook een OpenWeatherMap-account maken en een nieuwe applicatie-ID krijgen. Voeg de applicatie-ID toe aan een stringresource genaamd openWeather
.
XXXXXXXXXXXXXXX
Omdat de architectuurcomponenten nog steeds in alfa zijn, moet u de Google-repository, die een aantal experimentele bibliotheken bevat, opnemen in de projectreferenties. build.gradle
.
allprojects repositories // voeg deze repository toe maven url 'https://maven.google.com'
In de module build.gradle, voeg het volgende toe aan de afhankelijkheden
sectie om ondersteuning voor toe te voegen lifecycles
, Actuele gegevens
, en ViewModel
:
compileren "android.arch.lifecycle: runtime: 1.0.0-alpha5"
compileer "android.arch.lifecycle: extensions: 1.0.0-alpha5"
annotationProcessor "android.arch.lifecycle: compiler: 1.0.0-alpha5"
Als u Kotlin gebruikt, moet u ook de. Toevoegen of vervangen annotationProcessor
met Kapt
, die annotaties verwerkt op Kotlin.
kapt "android.arch.lifecycle: compiler: 1.0.0-alpha5"
In staat te stellen Kapt
, voeg het volgende toe in de module's build.gradle
wortel.
kapt generateStubs = true
Levenscyclus
bestanddeelElke Android-ontwikkelaar is bekend met het lifecycle-concept. Het systeem stuurt de levenscyclus van toepassingen, activiteiten, fragmenten, enzovoort, zonder de controle van de ontwikkelaar. Dit concept is een van de paradigma's van Android en tot voor kort was het niet zo eenvoudig om mee te werken, omdat het niet mogelijk was om direct te controleren op de huidige levenscyclusstatus van een component. Wat we konden doen, was reageren op bepaalde methoden, zoals onCreate
en onDestroy
, getriggerd door lifecycle-evenementen.
Dit is allemaal veranderd sinds de aankondiging van het pakket Architectuurcomponenten, dat een component introduceerde met de naam Levenscyclus
. Sommige Android-objecten hebben nu een Levenscyclus
gekoppeld, en dit verandert veel dingen voor de ontwikkelaars. Het is mogelijk om a te raadplegen Levenscyclus
staat op een bepaald moment, en het is ook mogelijk om te reageren op Levenscyclus
evenementen met behulp van annotaties. In feite is de backbone van de nieuwe Android Architecture Components de Levenscyclus
bestanddeel.
Alle elementen van het pakket android.arch.lifecycle
zijn belangrijk voor de levenscyclus concept, maar twee van hen verdienen meer aandacht: LifecycleOwner
en LifecycleObserver
. Ze creëren de mogelijkheid om mee te werken Levenscyclus
, observeren en reageren op gebeurtenissen die plaatsvinden op activiteiten, fragmenten, diensten enzovoort.
LifecycleOwner
De LifecycleOwner
is een enkele methode-interface voor klassen die een bevatten Levenscyclus
. Het abstraheert het bezit van een Levenscyclus
, zodat je componenten kunt schrijven die ermee kunnen werken. Door de nieuwe normen zijn Activiteiten en Fragmenten LifecycleOwner
s. Tot de definitieve versie van de architectuurcomponenten is gestart, moet u echter enkele speciale klassen gebruiken: ActivityLifecycle
, FragmentLifecycle
, en LifecycleService
.
class MainActivity: LifecycleActivity () override fun onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState)
Er is geen significante verandering in de implementatie van deze klassen in vergelijking met de standaardactiviteiten en fragmenten. Zodra een klas een van deze uitbreidt, heeft deze een Levenscyclus
bevestigd, die op elk moment met de methode kan worden opgehaald getLifecycle ()
. Een andere interessante mogelijkheid is dat we de huidige levenscyclusstatus kunnen controleren met getCurrentState
, welke een a retourneert Lifecycle.State
.
Er zijn er vijf Levenscyclus
luidt als volgt:
BEGONNEN
: voor een object dat is aangeroepen, maar dat nog niet "actief" is. Het is het equivalent van een staat vóór de Activity.onCreate
methode.CREATED
: voor objecten die zojuist zijn gemaakt. Het is genoemd naar de onCreate
methode en ook net voor de onStop
methode.BEGONNEN
: called after the onStart
en net voor de onPause
methode.HERVAT
: De actieve status of de hervatte status voor a LifecycleOwner
. Geroepen na de onResume
methode.VERNIETIGD
: voor een vernietigd LifecycleOwner
voorwerp. Deze Levenscyclus
zal niet meer evenementen verzenden. Dit evenement wordt bereikt vlak voor de onDestroy
methode.LifecycleObserver
Een van de meest interessante eigenschappen van de Levenscyclus
is dat het gemakkelijk kan worden waargenomen. LifecycleObserver
klassen kunnen waarnemen LifecycleOwner
componenten, zoals Activiteiten en Fragmenten. Het ontvangt LifecycleOwner.Event
s, en kan op hen reageren via de annotatie @OnLifeCycleEvent (Lifecycle.Event)
.
class MainObserver: LifecycleObserver, AnkoLogger @ OnLifecycleEvent (Lifecycle.Event.ON_RESUME) lol onResult () info ("onResult") @OnLifecycleEvent (Lifecycle.Event.ON_STOP) fun onStop () info ("onStop")
De geannoteerde methoden @OnLifecycleEvent
geen argumenten nodig, maar indien gebruikt, moet het eerste argument het zijn LifecycleOwner
. Wanneer de annotatie gebruikt Lifecycle.Event.ON_ANY
, de methode zou twee argumenten moeten verwachten: LifecycleOwner
en Lifecycle.Event
.
@ OnLifecycleEvent (Lifecycle.Event.ON_ANY) plezier opEvent (eigenaar: LifecycleOwner, event: Lifecycle.Event) info ("onEvent: ownerState: $ owner.lifecycle.currentState") info ("onEvent: event: $ event" )
Om de te activeren @OnLifecycleEvent
annotatie, de LifecycleObserver
moet een a observeren Levenscyclus
, anders zal het evenement niet worden ontvangen. Bel me om dit te laten werken Lifecycle.addObserver (LifecycleOwner)
en de LifecycleOwner
zal daarop kunnen reageren Lifecycle.Event
. Het is ook mogelijk om te bellen Lifecycle.removeObsever (LifecycleObserver)
om een waarnemer te verwijderen.
class MainActivity: LifecycleActivity (), AnkoLogger @Inject lateinit var mainObserver: MainObserver onderdrukt plezier onCreate (savedInstanceState: Bundle?) // ... // Op Kotlin, in plaats van getLifecycle, // kunnen we lifecycle direct lifecycle noemen.addObserver (mainObserver ) override fun onDestroy () // ... lifecycle.removeObserver (mainObserver)
Er zijn verschillende interessante use-cases voor LifecycleObserver
. Het kan bijvoorbeeld worden gebruikt om een te maken Presentator
laag uit het architectuurpatroon van Model View Presenter. Het kan ook worden gebruikt om luisteraars te maken die kunnen stoppen met luisteren wanneer het Levenscyclus
is gehandicapt.
LiveModel
bestanddeelOntworpen om samen te werken met de UI-laag, de ViewModel
component sluit een gat dat al sinds het begin in Android bestaat: biedt een manier om gegevensobjecten met betrekking tot de weergave elegant te beheren en op te slaan. Het onderdeel behoudt de gegevensintegriteit tussen configuratiewijzigingen, kan worden gedeeld tussen activiteit en fragmenten en is een uitstekend hulpmiddel om geheugenlekken volledig te voorkomen.
De ViewModel
wordt altijd gemaakt in nauwe relatie tot een specifiek bereik, een activiteit of een fragment. Het bereik blijft behouden zolang de activiteit of het fragment nog in leven is. In praktische termen, de ViewModel
maakt opnieuw verbinding met de weergave nadat de configuratie is gewijzigd en blijft zichzelf behouden tot de hoofdweergave is vernietigd. Volgens de officiële documentatie:
Het doel van de ViewModel
is om de informatie te verkrijgen en te bewaren die nodig is voor een Activiteit of een Fragment.
Op de top van dat alles, de ViewModel
vergemakkelijkt de scheiding van problemen in het Android-ontwikkelingsproces. Door alle gegevens gerelateerde bewerkingen naar dit onderdeel te verplaatsen en het de logica te laten verwerken, worden de testbaarheid en onderhoudbaarheid van de toepassing aanzienlijk verhoogd. Met ViewModel
, het is mogelijk om de Android-architectuur die op de Google I / O van 2017 wordt voorgesteld, eenvoudig te gebruiken. Je kunt het zelfs gebruiken om meer geavanceerde architectuurpatronen te adopteren, zoals MVP of MVVM.
ViewModel
Er zijn twee manieren om een te implementeren ViewModel
. De standaard is om de klasse uit te breiden en een constructeur zonder argument te leveren. Dit is de gemakkelijkste manier, maar het werkt niet goed met Dependency Injection.
class MainViewModel: ViewModel () init // initialize some behaviour fun getData (): LiveData// get some data override fun onCleared () super.onCleared () // called before its destruction
Om een te krijgen ViewModel
geconstrueerd met deze techniek uit een Activiteit of Fragment, bel gewoon ViewModelProviders.of (FragmentActivity) .get (Class
. Het laatste argument moet de ViewModel
klasse. Hetzelfde ViewModel
exemplaar wordt opgehaald door de weergave en bevat alle gegevens voor die weergave.
val viewModel: MainViewModel = ViewModelProviders.of (this) .get (MyViewModel :: class.java)
Merk op dat, sinds de ViewModel
is overgenomen van ViewModelProviders.of
methode, de constructor kan geen argumenten ontvangen. Als een tijdelijke oplossing kunt u een ViewModelProvider.Factory
. Eigenlijk is dit dezelfde techniek die we gebruiken om te injecteren ViewModel
.
ViewModel
Bij het gebruik van DI, wordt het een beetje lastiger. U moet een ViewModelProvider.Factory
. De volgende stappen kunnen worden gebruikt voor het injecteren van a ViewModel
met behulp van Dagger. De ViewModelFactory
is een utiliteitsklasse die een ViewModel
voor een scope.
@Suppress ("UNCHECKED_CAST") @Singleton class ViewModelFactory @Inject constructor (private val creators: Map, @JvmSuppressWildcards Provider >): ViewModelProvider.Factory leuk om op te ruimen create (modelClass: Class ): T var creator: Provider ? = creators [modelClass] if (creator == null) for ((sleutel, waarde) in makers) if (modelClass.isAignableFrom (key)) creator = value break if (creator == null) throw IllegalArgumentException ("onbekende modelklasse" + modelClass) probeer return creator.get () als T catch (e: Exception) throw RuntimeException (e)
Dolk heeft ook een @MapKey
gedefinieerd voor ViewModel
en een binder voor elk model en voor de fabriek in de module.
// @MapKey @MustBeDocumented @Target (AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) @ kotlin.annotation.Retention () @MapKey interne annotatieklasse ViewModelKey (val waarde: KClass) // ViewModel Module @Module abstracte klasse ViewModelsModule // Bind elk ViewModel @Binds @IntoMap @ViewModelKey (MainViewModel :: class) abstract fun bindMainViewModel (mainViewModel: MainViewModel): ViewModel // ViewModel factory binding @Binds abstract fun bindViewModelFactory (factory : ViewModelFactory): ViewModelProvider.Factory
Volg daarna de standaard Dagger-procedures en je kunt een ViewModel
in staat om argumenten in de constructor te injecteren. Als u een nieuw exemplaar wilt maken, haalt u het ViewModelFactory
en neem het gewenste ViewModel
ervan.
// Download de ViewModel-fabriek @Inject lateinit var viewModelFactory: ViewModelProvider.Factory // Get ViewModel val viewModel = ViewModelProviders.of (this, viewModelFactory) .get (MainViewModel :: class.java)
In ons voorbeeldproject kun je DI met behulp van Dagger van dichtbij bekijken. Ik heb je ook een map met voorbeelden gegeven in de tutorial GitHub repo met fragmenten die laten zien hoe te configureren ViewModels
op het dolksysteem met Kotlin.
class MainViewModel @Inject constructor (private val repository: MainRepository): ViewModel (), AnkoLogger // ... code gaat hier
Tot dusverre is onze reis door de nieuwe Android-architectuurcomponenten zeer productief geweest. We hebben echter nog steeds wat grond te dekken. In de volgende tutorial zullen we het hebben over het geweldige Actuele gegevens
component, onderzoekt de basis- en geavanceerde functies ervan en past deze concepten toe op onze voorbeeldtoepassing.
Tot ziens! En bekijk in de tussentijd een aantal van onze andere berichten over de ontwikkeling van Android-apps!