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.
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.
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.
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.
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 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.
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
.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.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
.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..
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.
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")
Actuele gegevens
bestanddeelDe 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"))
ViewModel
bestanddeelEen 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"))
Kamer
bestanddeelAndroid 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
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'
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!