09/10/2011
At udvikle en succesfuld Android-app handler om mere end blot at skrive kode, der virker. Det handler om at skabe en robust, skalerbar og vedligeholdelsesvenlig applikation, der kan modstå tidens tand og de uforudsigelige udfordringer, som mobilmiljøet byder på. En veldefineret arkitektur er fundamentet for dette. En typisk Android-app består af adskillige komponenter såsom aktiviteter, fragmenter, services og broadcast receivers. Disse komponenter erklæres i appens manifest, som Android-operativsystemet bruger til at integrere appen i enhedens overordnede brugeroplevelse. Da mobile enheder har begrænsede ressourcer, kan operativsystemet til enhver tid lukke app-processer for at frigøre plads. Dette betyder, at app-komponenter kan startes individuelt og i vilkårlig rækkefølge, og de kan blive ødelagt når som helst. Derfor bør man aldrig gemme app-data eller tilstand direkte i hukommelsen på disse komponenter.

Grundlæggende Arkitekturprincipper
Hvis app-komponenter ikke skal bruges til at gemme data og tilstand, hvordan designer man så sin app? Svaret ligger i at følge en række velafprøvede arkitekturprincipper, der sikrer, at din app er både robust og testbar.
Adskillelse af ansvarsområder (Separation of Concerns)
Det vigtigste princip er ansvarsadskillelse. En almindelig fejl er at skrive al kode i en Activity eller et Fragment. Disse UI-baserede klasser bør kun indeholde logik, der håndterer UI og interaktioner med operativsystemet. Ved at holde disse klasser så rene som muligt undgår man mange problemer relateret til komponenternes livscyklus og forbedrer deres testbarhed markant. Husk, at du ikke ejer implementeringerne af Activity og Fragment; de er blot en kontrakt mellem din app og Android OS. OS'et kan ødelægge dem når som helst. For at levere en god brugeroplevelse og en mere håndterbar app, er det bedst at minimere afhængigheden af dem.
Styr UI fra Datamodeller
Et andet centralt princip er at drive din brugergrænseflade (UI) fra datamodeller, helst persistente modeller. Datamodeller repræsenterer appens data og er uafhængige af UI-elementer og andre app-komponenter. De er ikke bundet til UI'ets livscyklus og bliver kun ødelagt, når OS'et fjerner appens proces fra hukommelsen. Persistente modeller er ideelle, fordi:
- Brugerne mister ikke data, hvis Android OS ødelægger din app for at frigøre ressourcer.
- Appen fortsætter med at fungere, selv når netværksforbindelsen er dårlig eller fraværende.
Ved at basere din arkitektur på datamodelklasser forbedrer du appens testbarhed og robusthed.

Single Source of Truth (SSOT)
Når du definerer en ny datatype i din app, bør du tildele den en "Single Source of Truth" (SSOT). SSOT er ejeren af disse data, og kun SSOT kan ændre dem. For at opnå dette eksponerer SSOT dataene som en uforanderlig type og tilbyder funktioner eller modtager hændelser, som andre typer kan kalde for at anmode om ændringer. Dette mønster giver flere fordele:
- Centraliserer alle ændringer til en bestemt datatype ét sted.
- Beskytter data mod at blive manipuleret af andre typer.
- Gør dataændringer mere sporbare, hvilket gør fejl lettere at finde.
Envejs Dataflow (Unidirectional Data Flow - UDF)
SSOT-princippet bruges ofte sammen med et envejs dataflow-mønster (UDF). I UDF flyder tilstand (state) kun i én retning. Hændelser (events), der modificerer data, flyder i den modsatte retning. I Android flyder tilstand typisk fra højere hierarkiske typer (som datakilder) ned til lavere typer (som UI). Brugerhændelser, som et tryk på en knap, flyder fra UI'et op til SSOT, hvor dataene modificeres. Dette mønster sikrer datakonsistens, er mindre fejlbehæftet og lettere at debugge.
Anbefalet App-arkitektur
Baseret på de ovennævnte principper bør enhver moderne Android-app have mindst to lag: UI-laget og datalaget. Man kan også tilføje et valgfrit domænelag for at forenkle interaktioner.
UI-laget (The UI Layer)
UI-lagets funktion er at vise applikationsdata på skærmen. Når data ændrer sig, enten på grund af brugerinteraktion eller eksternt input, skal UI'et opdateres. UI-laget består af to hovedelementer:
- UI-elementer: Disse gengiver data på skærmen. De kan bygges med Views eller Jetpack Compose-funktioner.
- Tilstandsbeholdere (State Holders): Klasser som ViewModel, der holder på data, eksponerer dem for UI'et og håndterer logikken.
Datalaget (The Data Layer)
Datalaget indeholder appens forretningslogik og er ansvarlig for at oprette, gemme og ændre data. Dette lag består typisk af Repositories, som hver især håndterer en bestemt type data (f.eks. MoviesRepository eller PaymentsRepository). Et Repository er ansvarligt for at:
- Eksponere data til resten af appen.
- Centralisere dataændringer.
- Løse konflikter mellem flere datakilder (f.eks. netværk og lokal database).
- Abstrahere datakilder væk fra resten af appen.
Domænelaget (The Domain Layer)
Dette er et valgfrit lag placeret mellem UI- og datalaget. Domænelaget er ansvarligt for at indkapsle kompleks forretningslogik eller simpel logik, der genbruges af flere ViewModels. Klasser i dette lag kaldes ofte Use Cases eller Interactors. Man bør kun bruge dette lag, når det er nødvendigt for at håndtere kompleksitet eller fremme genbrugelighed.
| Lag | Primært Ansvar | Eksempler på Komponenter |
|---|---|---|
| UI-laget | Vise data på skærmen, håndtere brugerinteraktion. | Activities, Fragments, ViewModels, Composables |
| Domænelaget (Valgfrit) | Indkapsle kompleks eller genbrugelig forretningslogik. | Use Cases, Interactors |
| Datalaget | Håndtere app-data og forretningsregler, eksponere data. | Repositories, Data Sources (API, Database) |
Fundamentet: Androids Operativsystem-arkitektur
For at forstå, hvordan denne app-arkitektur fungerer i praksis, er det også vigtigt at have en grundlæggende viden om selve Android-operativsystemets opbygning. Android OS er en stak af softwarekomponenter, der groft kan opdeles i fem sektioner og fire hovedlag.

Linux-kernen (Linux Kernel)
I bunden af stakken ligger Linux-kernen. Dette er kernen i operativsystemet og udgør et abstraktionslag mellem enhedens hardware og resten af softwarestakken. Kernen indeholder alle de essentielle hardwaredrivere til f.eks. kamera, tastatur og skærm. Den håndterer også grundlæggende systemfunktioner som netværk, hukommelsesstyring og processer, hvilket er ting, Linux er rigtig god til.
Biblioteker (Libraries)
Oven på Linux-kernen findes et sæt af C/C++ biblioteker. Disse inkluderer velkendte open source-biblioteker som:
- WebKit: En browser-engine, der bruges til at vise webindhold.
- libc: Standard C-biblioteket.
- SQLite: En letvægtsdatabase til lagring og deling af applikationsdata.
- Media-biblioteker: Til afspilning og optagelse af lyd og video.
- SSL: Til at sikre internetforbindelser.
Android Runtime
Dette lag indeholder nøglekomponenten Dalvik Virtual Machine (eller ART - Android Runtime, i nyere versioner), som er en virtuel maskine optimeret til mobile enheder. Hver Android-applikation kører i sin egen proces med sin egen instans af den virtuelle maskine. Android Runtime inkluderer også et sæt kernebiblioteker, der gør det muligt for udviklere at skrive Android-apps ved hjælp af Java- eller Kotlin-programmeringssproget.
Applikationsrammeværk (Application Framework)
Dette lag tilbyder højniveautjenester til apps i form af Java-klasser. Udviklere kan bruge disse tjenester i deres applikationer. Nogle af de vigtigste tjenester er:
- Activity Manager: Styrer alle aspekter af en applikations livscyklus og aktivitetsstak.
- Content Providers: Gør det muligt for apps at udgive og dele data med andre apps.
- Resource Manager: Giver adgang til ikke-kode ressourcer som strenge, farver og UI-layouts.
- Notifications Manager: Gør det muligt for apps at vise alarmer og notifikationer til brugeren.
- View System: Et udvideligt sæt af views, der bruges til at bygge applikationers brugergrænseflader.
Applikationer (Applications)
På det øverste lag finder man alle applikationerne. Dette er laget, hvor både de præinstallerede systemapps (Kontakter, Browser, osv.) og de apps, du selv installerer, ligger. Når du udvikler en app, er det på dette lag, den vil blive installeret og kørt.
Ofte Stillede Spørgsmål (FAQ)
- Hvorfor er det vigtigt at adskille UI-logik fra forretningslogik?
- Det er afgørende for at forbedre appens testbarhed, vedligeholdelse og robusthed. UI-komponenter som Activities og Fragments styres af operativsystemet og kan blive ødelagt når som helst. Ved at holde forretningslogikken separat sikrer du, at vigtige data og processer ikke går tabt, og at koden er lettere at teste uafhængigt af UI'et.
- Hvad er en "Single Source of Truth" (SSOT)?
- SSOT er et designprincip, hvor en enkelt komponent eller et enkelt lag (ofte et Repository i datalaget) har ejerskabet over en bestemt type data. Kun denne "sandhedskilde" kan modificere dataene. Dette centraliserer datahåndtering, forhindrer inkonsistens og gør fejlfinding meget lettere.
- Er domænelaget altid nødvendigt?
- Nej, domænelaget er valgfrit. Det bør kun implementeres, når appen har kompleks forretningslogik, der skal genbruges på tværs af flere ViewModels, eller når logikken er så kompliceret, at det er en fordel at isolere den fra datalaget for at forbedre læsbarheden og testbarheden.
- Hvad er den laveste del af Androids arkitektur?
- Den laveste og mest fundamentale del er Linux-kernen. Den fungerer som et bro mellem enhedens hardware og resten af softwaren, og den håndterer kernefunktioner som drivere, strømstyring og hukommelsesstyring.
Hvis du vil læse andre artikler, der ligner Guide til Android App-arkitektur, kan du besøge kategorien Teknologi.
