Android-architectuurcomponenten lifecycle en LiveModel

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!

  • Codering Functionele Android-apps in Kotlin: Aan de slag

    Heb je positieve dingen gehoord over de Kotlin-taal voor Android-apps en wil je het zelf proberen? Ontdek hoe u de codering in deze nieuwe ...
    Jessica Thornsby
    Android Studio
  • Codering van functionele Android-apps in Kotlin: Lambdas, Null Safety & More

    Met de Kotlin-taal voor Android-apps kun je coderen, dat in Java veel veelzeggender zou zijn of niet mogelijk met alleen Java. Leren hoe…
    Jessica Thornsby
    Android SDK

1. Het voorbeeldproject

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.

Hoe werkt de app?

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.

De voorbeeld-app uitvoeren

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

2. Een project opzetten

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 lifecyclesActuele 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

3. De Levenscyclus bestanddeel

Elke 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.

De 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 LifecycleOwners. Tot de definitieve versie van de architectuurcomponenten is gestart, moet u echter enkele speciale klassen gebruiken: ActivityLifecycleFragmentLifecycle, 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.

De 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.Events, 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.

4. Het LiveModel bestanddeel

Ontworpen 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.

Implementatie van een 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.

Injecteren van een 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

Conclusie

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!