Inleiding tot Android-architectuurcomponenten

Android is in 2005 wereldwijd geïntroduceerd en gedurende die 12 jaar heeft het platform verbazingwekkend succes geboekt en is het het meest geïnstalleerde mobiele besturingssysteem geworden. In die tijd zijn 14 verschillende versies van het besturingssysteem geïntroduceerd, waarbij Android steeds volwassener wordt. Een zeer belangrijk deel van het platform bleef echter genegeerd: een standaardarchitectuurpatroon dat in staat is om de eigenaardigheden van het platform te hanteren en eenvoudig genoeg om door de gemiddelde ontwikkelaar te worden begrepen en aanvaard..

Wel, beter laat dan nooit. Bij de laatste Google I / O besloot het Android-team eindelijk om dit probleem aan te pakken en te reageren op de feedback van ontwikkelaars over de hele wereld, een officiële aanbeveling voor een Android-applicatiearchitectuur aan te kondigen en de bouwstenen te leveren om het te implementeren: de nieuwe architectuur componenten. En beter nog, ze zijn erin geslaagd het te doen zonder de openheid van het systeem dat we allemaal kennen en liefhebben in gevaar te brengen.

In deze zelfstudie verkennen we de gestandaardiseerde architectuur die wordt voorgesteld door het Android-team op Google I / O en bekijken we de belangrijkste elementen van de nieuwe architectuurcomponenten: Levenscyclus, ViewModel, LifeData, en Kamer. We zullen niet te veel aandacht besteden aan de code, maar focussen op het concept en de logica achter deze thema's. We zullen ook enkele eenvoudige fragmenten bekijken, allemaal geschreven met Kotlin, een verbazingwekkende taal die nu officieel door Android wordt ondersteund.

1. Wat was Android verdwenen?

Als je net begint aan je reis als ontwikkelaar, is het mogelijk dat je niet precies weet waar ik het over heb. Toepassingsarchitectuur kan immers in eerste instantie een obscuur thema zijn. Maar geloof me, je zult het belang ervan snel genoeg leren! Naarmate een applicatie groeit en complexer wordt, zal haar architectuur steeds belangrijker worden. Het kan letterlijk je werk tot een geluk maken of tot een hel maken.

Applicatiearchitectuur

Om het even ruw te stellen: een applicatiearchitectuur is een consistent plan dat moet worden gemaakt voordat het ontwikkelingsproces begint. Dit plan biedt een kaart van hoe de verschillende toepassingscomponenten moeten worden georganiseerd en met elkaar worden verbonden. Het bevat richtlijnen die tijdens het ontwikkelingsproces moeten worden gevolgd en die enkele offers (meestal in verband met meer klassen en standaardzones) met zich meebrengen die uiteindelijk helpen bij het opstellen van een goed geschreven toepassing die beter controleerbaar, uitbreidbaar en onderhoudbaar is.

Software applicatie architectuur is het proces van het definiëren van een gestructureerde oplossing die voldoet aan alle technische en operationele vereisten, terwijl het gemeenschappelijke kwaliteitskenmerken zoals prestaties, veiligheid en beheersbaarheid optimaliseert. Het omvat een reeks beslissingen op basis van een breed scala aan factoren, en elk van deze beslissingen kan een aanzienlijke invloed hebben op de kwaliteit, prestaties, onderhoudbaarheid en algehele succes van de toepassing..
- Microsoft's Software Architecture and Design Guide

Een goede architectuur houdt rekening met veel factoren, met name de systeemkenmerken en limieten. Er zijn veel verschillende architecturale oplossingen, allemaal met voor- en nadelen. Sommige sleutelbegrippen zijn echter gemeenschappelijk tussen alle visies.

Oude fouten

Tot de laatste Google I / O beval het Android-systeem geen specifieke architectuur aan voor de ontwikkeling van toepassingen. Dat betekent dat je volledig vrij was om elk model te adopteren: MVP, MVC, MVPP, of zelfs helemaal geen patroon. Daarenboven bood het Android-framework zelfs geen native oplossingen voor problemen die door het systeem zelf werden gecreëerd, met name de levenscyclus van de component.

Als u dus een Model View Presenter-patroon op uw toepassing wilde toepassen, moest u uw eigen oplossing helemaal zelf bedenken, veel standaardcode schrijven of een bibliotheek zonder officiële ondersteuning adopteren. En die afwezigheid van standaarden zorgde voor veel slecht geschreven applicaties, met codebases die moeilijk te onderhouden en te testen waren. 

Zoals ik al zei, is deze situatie al jaren bekritiseerd. In feite heb ik onlangs over dit probleem geschreven en hoe ik het kan aanpakken in mijn Hoe modelweergave aan te nemen in de Android-serie. Maar het belangrijkste is dat na twaalf lange jaren het Android-team uiteindelijk besloot om naar onze klachten te luisteren en ons met dit probleem te helpen.

2. Android-architectuur

De nieuwe Android Architecture Guide definieert een aantal belangrijke principes waaraan een goede Android-applicatie moet voldoen en biedt ook een veilig pad voor de ontwikkelaar om een ​​goede app te maken. De gids vermeldt echter expliciet dat de gepresenteerde route niet verplicht is en dat de beslissing uiteindelijk persoonlijk is; het is de ontwikkelaar die moet beslissen welk type architectuur hij moet adopteren.

Volgens de gids moet een goede Android-applicatie zorgen voor een stevige scheiding van zorgen en de gebruikersinterface van een model verdrijven. Elke code die geen UI of besturingssysteeminteractie aankan, mag niet in een Activiteit of Fragment staan, omdat het houden van deze code zo schoon mogelijk is, zodat u veel levenscyclusproblemen kunt vermijden. Het systeem kan immers op elk moment Activiteiten of Fragmenten vernietigen. Ook moeten de gegevens worden verwerkt door modellen die geïsoleerd zijn van de gebruikersinterface en bijgevolg van problemen met de levenscyclus.

De nieuwe aanbevolen architectuur

De architectuur die door Android wordt aanbevolen, kan niet eenvoudig worden geëtiketteerd tussen de standaardpatronen die we kennen. Het ziet eruit als een Model View Controller-patroon, maar het is zo nauw verbonden met de architectuur van het systeem dat het moeilijk is om elk element te labelen met de bekende conventies. Dit is echter niet relevant, omdat het belangrijk is dat het afhankelijk is van de nieuwe architectuurcomponenten om een ​​scheiding van zorgen te creëren, met uitstekende testbaarheid en onderhoudbaarheid. En beter nog, het is eenvoudig te implementeren.

Om te begrijpen wat het Android-team voorstelt, moeten we alle elementen van de architectuurcomponenten kennen, want zij zijn degenen die het zware werk voor ons zullen doen. Er zijn vier componenten, elk met een specifieke rol: Kamer, ViewModel, Actuele gegevens, en Levenscyclus. Al deze onderdelen hebben hun eigen verantwoordelijkheden en ze werken samen om een ​​solide architectuur te creëren. Laten we een vereenvoudigd schema van de voorgestelde architectuur bekijken om het beter te begrijpen.

Zoals u kunt zien, hebben we drie hoofdelementen, elk met zijn verantwoordelijkheid. 

  1. De Activiteit en Fragment vertegenwoordig de Uitzicht laag, die niet te maken heeft met bedrijfslogica en complexe operaties. Het configureert alleen de weergave, behandelt de gebruikersinteractie en, het belangrijkste, observeert en vertoont Actuele gegevens elementen uit de ViewModel.
  2. De ViewModel neemt automatisch de Levenscyclus status van het beeld, behoud van consistentie tijdens configuratiewijzigingen en andere Android lifecycle-evenementen. Het wordt ook geëist door de weergave om gegevens van de te halen bewaarplaats, welke als waarneembaar wordt verschaft Actuele gegevens. Het is belangrijk om te begrijpen dat de ViewModel nooit refereert aan de Uitzicht rechtstreeks en dat de updates van de gegevens altijd worden gedaan door de Actuele gegevens entiteit.
  3. De bewaarplaats is geen speciaal Android-onderdeel. Het is een eenvoudige klasse, zonder enige specifieke implementatie, die verantwoordelijk is voor het ophalen van gegevens uit alle beschikbare bronnen, van een database tot webservices. Het behandelt al deze gegevens, in het algemeen transformeert ze naar waarneembaar Actuele gegevens en ze beschikbaar te maken voor de ViewModel.
  4. De Kamer database is een SQLite-mappingbibliotheek die het verwerken van een database vergemakkelijkt. Het schrijft automatisch een heleboel boilerplate, controleert fouten tijdens het compileren en het beste van alles is dat het direct query's kan teruggeven met waarneembaar Actuele gegevens.

Ik weet zeker dat je hebt opgemerkt dat we veel hebben gesproken over waarnemingen. The Observer Pattern is een van de grondslagen van de Actuele gegevens element en Levenscyclus bewuste componenten. Met dit patroon kan een object een lijst met waarnemers informeren over wijzigingen in de status of gegevens. Dus wanneer een activiteit een a observeert Actuele gegevens entiteit, zal deze updates ontvangen wanneer die gegevens enige vorm van wijziging ondergaan.

Een andere Android-aanbeveling is om de architectuur te consolideren met behulp van een Dependency Injection-systeem, zoals Google's Dagger 2 of met behulp van het Service Locator-patroon (wat veel eenvoudiger is dan DI, maar zonder veel van zijn voordelen). In deze zelfstudie behandelen we DI of Service Locator niet, maar Envato Tuts + heeft een aantal uitstekende zelfstudies over die thema's. Houd er echter rekening mee dat er enkele bijzonderheden zijn van het werken met Dagger 2 en Android-componenten die in het tweede deel van deze serie zullen worden uitgelegd..

3. Architectuurcomponenten

We moeten diep in de aspecten van de nieuwe componenten duiken om dit model van architectuur echt te kunnen begrijpen en adopteren. We zullen echter niet in detail treden in deze tutorial. Vanwege de complexiteit van elk element, in deze zelfstudie, praten we alleen over het algemene idee achter elk element en bekijken we enkele vereenvoudigde codefragmenten. We zullen proberen voldoende grond te bieden om de componenten te presenteren en u op weg te helpen. Maar wees niet bang, want toekomstige artikelen in deze serie zullen diep graven en alle bijzonderheden van de architectuurcomponenten behandelen.

Lifecycle-Aware-componenten

Op de meeste Android-app-componenten zijn levenscycli aangesloten die rechtstreeks door het systeem zelf worden beheerd. Tot voor kort was het aan de ontwikkelaar om de status van de componenten te bewaken en dienovereenkomstig te handelen, waarbij taken op het juiste moment werden geïnitialiseerd en beëindigd. Het was echter heel gemakkelijk om in de war te raken en fouten te maken met betrekking tot dit type operatie. Maar de android.arch.lifecycle pakket heeft dat allemaal veranderd. 

Nu hebben Activiteiten en Fragmenten een Levenscyclus object daaraan gehecht dat kan worden waargenomen door LifecycleObserver klassen, zoals a ViewModel of een object dat deze interface implementeert. Dat betekent dat de waarnemer updates ontvangt over de statuswijzigingen van het object dat wordt waargenomen, zoals wanneer een activiteit is onderbroken of wanneer deze wordt gestart. Het kan ook de huidige status van het waargenomen object controleren. Het is nu veel gemakkelijker om bewerkingen uit te voeren die rekening moeten houden met de levenscyclus van frameworks.

Voor nu, om een ​​te maken Activiteit of Fragment die voldoet aan deze nieuwe standaard, moet je een LifecycleActivity of LifecycleFragment. Het is echter mogelijk dat dit niet altijd nodig zal zijn, omdat het Android-team ernaar streeft om deze nieuwe tools volledig te integreren met het framework.

class MainActivity: LifecycleActivity () override fun onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main)

De LifecycleObserver ontvangt Levenscyclus evenementen en kan reageren via annotatie. Er is geen methode-override nodig.

class MainActivityObserver: LifecycleObserver, AnkoLogger @ OnLifecycleEvent (Lifecycle.Event.ON_RESUME) fun onResume () info ("onResume") @OnLifecycleEvent (Lifecycle.Event.ON_PAUSE) fun onPause () info ("onPause")

De Actuele gegevens bestanddeel

De Actuele gegevens component is een gegevenshouder die een waarde bevat die kan worden waargenomen. Gezien het feit dat de waarnemer heeft voorzien in een Levenscyclus tijdens de Actuele gegevens instantiatie, Actuele gegevens zal zich gedragen volgens Levenscyclus staat. Als de waarnemer  Levenscyclus toestand is BEGONNEN of HERVAT, de waarnemer is actief; anders is het dat wel inactief

Actuele gegevens weet wanneer de gegevens zijn gewijzigd en ook of de waarnemer is actief en zou een update moeten ontvangen. Een ander interessant kenmerk van de Actuele gegevens is dat het in staat is om de waarnemer te verwijderen als hij in een Lifecycle.State.DESTROYED staat, vermijdt geheugenlekken wanneer waargenomen door Activiteiten en Fragmenten.

EEN Actuele gegevens moet implementeren onActive en onInactive methoden.

class LocationLiveData (context: Context): LiveData(), AnkoLogger, LocationListener private val locationManager: LocationManager = context.getSystemService (Context.LOCATION_SERVICE) als LocationManager-opheffingsplezier opActive () info ("onActive") locationManager.requestLocationUpdates (LocationManager.GPS_PROVIDER, 0, 0f, this) override fun onInactive () info ("onInactive") locationManager.removeUpdates (this) // ...

Om een ​​te observeren Actuele gegevens component, moet u bellen waarnemer (LifecycleOwner, Observer).

class MainActivity: LifecycleActivity (), AnkoLogger fun observedLocation () val location = LocationLiveData (this) location.observe (this, Observer location -> info ("location: $ location"))

De ViewModel bestanddeel

Een van de belangrijkste klassen van de nieuwe architectuurcomponenten is de ViewModel, die is ontworpen om gegevens te bevatten die gerelateerd zijn aan de gebruikersinterface, waarbij de integriteit behouden blijft tijdens configuratiewijzigingen zoals schermrotaties. De ViewModel kan praten met de bewaarplaats, krijgen Actuele gegevens van het en het op zijn beurt beschikbaar maken om te worden bekeken door het uitzicht. ViewModel hoeft ook geen nieuwe oproepen te doen naar de bewaarplaats na configuratiewijzigingen, die de code veel optimaliseert.

Als u een weergavemodel wilt maken, breidt u het ViewModel klasse.

class MainActivityViewModel: ViewModel () private var notes: MutableLiveData>? = null leuk getNotes (): LiveData> if (notes == null) notes = MutableLiveData> () loadNotes () return-opmerkingen !!  private funload Loadotes () // async-bewerking uitvoeren om notities op te halen

Als u vanuit een weergave wilt openen, kunt u bellen ViewProviders.of (Activiteit | Fragment) .get (ViewModel :: klasse). Deze fabrieksmethode retourneert een nieuw exemplaar van de ViewModel of neem de behoudene, voor zover van toepassing. 

class MainActivity: LifecycleActivity (), AnkoLogger override fun onCreate (savedInstanceState: Bundle?) super.onCreate (savedInstanceState) setContentView (R.layout.activity_main) val viewModel = ViewModelProviders.of (this) .get (MainActivityViewModel :: class. java) viewModel.getNotes (). observe (this, Observer notes -> info ("notes: $ notes"))

De Kamer bestanddeel

Android heeft vanaf het begin SQLite ondersteund; Om het echter te laten werken, was het altijd nodig om veel standaards te schrijven. SQLite heeft ook geen POJO's (gewone oude Java-objecten) opgeslagen en heeft tijdens het compileren geen query's gecontroleerd. Komt Kamer om deze problemen op te lossen! Het is een SQLite-mappingbibliotheek die Java-POJO's kan behouden, query's direct omzet in objecten, fouten tijdens het compileren controleert en produceert Actuele gegevens waarnemingen uit queryresultaten. Kamer is een Object Relational Mapping-bibliotheek met een aantal coole Android-extra's.

Tot nu toe kon je het meeste van wat doen Kamer is in staat andere ORM Android-bibliotheken te gebruiken. Geen van hen wordt echter officieel ondersteund en, belangrijker nog, ze kunnen niet produceren LifeData resultaten. De Kamer bibliotheek past perfect als de blijvende laag op de voorgestelde Android-architectuur.

Om een ​​te maken Kamer database, heb je een @Entiteit volharden, wat elke Java POJO kan zijn, a @Dao interface om query's en invoer / uitvoerbewerkingen uit te voeren en a @Database abstracte klasse die moet worden uitgebreid RoomDatabase.

@Entity-klasse Opmerking @PrimaryKey var id: lang? = null var text: String? = null var date: lang? = null
@Dao interface NoteDAO @Insert (onConflict = OnConflictStrategy.REPLACE) fun insertNote (let op: Opmerking): Long @Update (onConflict = OnConflictStrategy.REPLACE) leuke updateNote (let op: Opmerking): Int @ Delleete fun deleteNote (let op: Opmerking) : Int @Query ("SELECT * FROM note") fun findAllNotes (): LiveData // op Kotlin worden de queryargumenten hernoemd // naar arg [N], zijnde N het argumentnummer. // op Java nemen de argumenten de oorspronkelijke naam @Query aan ("SELECT * FROM note WHERE id =: arg0") fun findNoteById (id: Long): LiveData 
@Database (entities = arrayOf (Note :: class), version = 1) abstract class Databse: RoomDatabase () abstract fun noteDAO (): NoteDAO

Architectuurcomponenten aan uw project toevoegen

Om nu de nieuwe architectuurcomponenten te gebruiken, moet je eerst de Google-repository aan je toevoegen build.gradle het dossier. Raadpleeg de officiële gids voor meer informatie.

allprojects repositories jcenter () // Google-repository toevoegen maven url 'https://maven.google.com'

Conclusie

Zoals u kunt zien, heeft de gestandaardiseerde architectuur van Android veel concepten nodig. Verwacht nog geen volledig begrip van dit onderwerp. We introduceren tenslotte alleen maar het thema. Maar je hebt nu zeker voldoende kennis om de logica achter de architectuur en de rollen van de verschillende Architectuurcomponenten te begrijpen.

We hebben het gehad over de meeste onderwerpen die verband houden met de voorgestelde Android-architectuur en de bijbehorende componenten; echter, details over de implementatie van componenten en enkele extra's, zoals de bewaarplaats klasse en het Dagger 2-systeem kunnen niet worden gedekt door dit eerste deel. We zullen die thema's in de volgende berichten onderzoeken.

Tot ziens!