12+ Jahre App-Entwicklung
Schnell mit KI, stark durch Erfahrung
50+ Erfolgreiche App-Projekte

Blog

Jetpack Compose: Googles modernes UI-Toolkit

Fast zwei Jahre nach der stabilen Veröffentlichung von Jetpack Compose sind viele Entwickler noch immer skeptisch, ob sich das Framework für eigene Projekte lohnt. Um diese Frage zu beantworten, vergleichen wir Android Views und Jetpack Compose anhand typischer Aufgaben in nativen Android-Projekten.

Artikelbild für Jetpack Compose: Googles modernes UI-Toolkit

Die Entscheidung zwischen Android Views und Jetpack Compose ist für jede moderne Android App Entwicklung relevant, denn sie prägt Entwicklungsgeschwindigkeit, Wartbarkeit und den Aufwand zukünftiger Erweiterungen.

Schauen wir uns Jetpack Compose anhand der folgenden Themen an:

Ist Jetpack Compose wirklich so gut, wie Google sagt?

Google bezeichnet Jetpack Compose als leistungsstarkes, intuitives und modernes Toolkit für native Benutzeroberflächen, das im Vergleich zu Android Views deutlich weniger Code erfordert. Testen wir diese Aussagen anhand eines einfachen Beispiels: einer scrollbaren Liste von Elementen.

boxes list

Wir erstellen eine Liste von Boxen auf Basis der OpenSenseMap API. Jedes Listenelement soll den Namen der Box sowie die Anzahl ihrer Sensoren anzeigen. Links sieht man, wie die Markup-Datei eines Listenelements in Android Views aussehen würde, rechts die Umsetzung desselben Elements in Jetpack Compose.

Box list item Android View  Box list item Jetpack Compose

Ich denke, es ist gut zu erkennen, dass der mit Jetpack Compose geschriebene Code nicht nur kürzer, sondern auch deutlich übersichtlicher ist. Die Anordnung der Elemente basiert in Compose vor allem auf Row und Column, was zusammen mit der Stärke von Kotlin die UI-Erstellung erheblich vereinfacht. Schauen wir uns als Nächstes die Initialisierung dieser Liste an.

Box list adpter Android View  Box list adpter Jetpack Compose

Bei Android Views brauchen wir für einen RecyclerView einen BoxListAdapter sowie einen passenden BoxHolder. In Jetpack Compose genügt eine Funktion, die wiederum die Composable LazyColumn enthält - gewissermaßen das Compose-Pendant zum RecyclerView. Wir übergeben einfach eine Liste von Elementen und rufen innerhalb einer Lambda für jedes Element die zuvor definierte Composable BoxListItem auf. Der Unterschied ist erheblich.

Nehmen wir ein weiteres Beispiel: Navigation zwischen Composable Functions.

Compose navigation function  Сompose navigation interface

Navigation in Jetpack Compose kann viele der Funktionen nutzen, die wir aus Jetpack Navigation kennen. Gleichzeitig haben wir mit Compose die Möglichkeit, zwischen Screens - also Composable Functions - innerhalb einer einzigen Activity zu navigieren, ohne Fragments zu benötigen. Es reicht, einen NavHost zu definieren und darin die einzelnen Screen-Composables zu verschachteln. Zur besseren Strukturierung kann zusätzlich ein Interface oder eine vergleichbare Abstraktion verwendet werden, in dem Routen und Parameter definiert sind.

ui folders

Man erkennt gut, wie elegant sich die für die UI verantwortlichen Dateien nun gruppieren lassen. Der Wegfall unzähliger XML-Dateien, Fragments und Adapter trägt wesentlich dazu bei.

Deklarative vs. imperative UI-Erstellung in Android

Historisch wurde die Hierarchie von Android-UI-Elementen als Widget-Baum aufgebaut. Wenn sich der Zustand der Anwendung ändert, muss dieser Baum aktualisiert werden, damit aktuelle Daten sichtbar werden. Die häufigste Vorgehensweise besteht darin, den Baum per Funktionen zu durchlaufen und über Methodenaufrufe den Zustand einzelner Views zu verändern.

Das manuelle Manipulieren von Views erhöht jedoch die Fehleranfälligkeit. Wenn ein Stück Information an mehreren Stellen angezeigt wird, kann leicht vergessen werden, eine dieser Stellen ebenfalls zu aktualisieren. Ebenso entstehen schnell fehlerhafte Zustände, wenn zwei Updates unerwartet miteinander kollidieren. Ein Update könnte zum Beispiel versuchen, einen Knoten zu verändern, der gerade aus der UI entfernt wurde. Mit steigender Zahl zu aktualisierender Views wächst also auch die Komplexität in Wartung und Fehlersuche.

declarative vs imperativ ui

Designed by Freepik

Der deklarative Ansatz ist ein moderner Entwicklungstrend, bei dem die Benutzeroberfläche ausgehend von Daten und Zustand gedacht wird. Der Fokus liegt primär auf der Frage: Was soll dargestellt werden? Eine deklarative UI bedeutet, das Design der Anwendung neu zu denken und zu akzeptieren, dass Teile der Oberfläche bei Änderungen vollständig neu aufgebaut werden können, statt sie schrittweise zu mutieren. Moderne Prozessoren sind dafür schnell genug und können sogar Animationen parallel zu vollständigen Rebuilds bewältigen.

In einem deklarativen Framework führen Zustandsänderungen zu einem UI-Rebuild. Dadurch verschwindet eine ganze Klasse typischer Zustandsfehler, und Updates werden leichter nachvollziehbar. Man beschreibt nur noch, wie die Oberfläche für einen bestimmten Zustand aussehen soll - das Framework kümmert sich um das Wie. Das reduziert die Menge des nötigen Codes erheblich und macht wiederkehrende Muster einfacher handhabbar.

State Holder, UI State und unidirektionaler Datenfluss

Compose basiert auf einem unidirektionalen Datenfluss. Im Gegensatz zum älteren UI-System sollten Composable Functions selbst zustandslos sein. Das bedeutet: Ihre Darstellung ergibt sich aus den Argumenten, die ihnen übergeben werden.

unidirectional data flow pattern

Source: Google Documentation

Das heißt konkret: Ereignisse, die entweder aus der Oberfläche kommen - etwa Button-Klicks oder Texteingaben - oder aus anderen Quellen wie API-Calls oder Callbacks, werden von einer Logikschicht verarbeitet. Diese aktualisiert den Zustand der UI und gibt ihn an die Composable Functions weiter. Da Composables selbst keinen Zustand speichern sollen, bestimmt der übergebene Zustand vollständig, wie die Oberfläche aufgebaut wird. Einen State Holder kann man dafür entweder über ein ViewModel oder eine einfache Klasse realisieren. Schauen wir uns ein Beispiel mit ViewModel an.

ViewModel with UI StateUI State processing

Für die Kommunikation zwischen ViewModel und Composable Function bietet es sich an, Observable State und MutableState für das State-Management zu verwenden. Alternativ können auch LiveData oder Flow genutzt werden, indem sie über die Erweiterungsfunktionen observeAsState() und collectAsState() in State umgewandelt werden. Im ViewModel lässt sich zudem ein sealed interface definieren, in dem alle benötigten Zustände gesammelt werden. Diese Zustände können anschließend ausgewertet und zur passenden Composable weitergereicht werden.

Vor- und Nachteile von Jetpack Compose

Vorteile

  • Der erste Vorteil ist die niedrige Einstiegshürde. Das liegt vor allem daran, dass die UI in derselben Sprache entwickelt wird wie die App-Logik - also in Kotlin. Das Jetpack-Compose-Team orientiert sich außerdem an modernen Best Practices, reduziert Boilerplate und liefert gute Dokumentation auf der offiziellen Google-Dokumentationsseite.
  • Ein weiterer wichtiger Vorteil ist die Kompatibilität. Bestehende Projekte müssen nicht vollständig neu geschrieben werden - Compose kann gezielt dort eingesetzt werden, wo es sinnvoll ist. Die API funktioniert in beide Richtungen: Composable Functions können in XML genutzt werden, und Composables selbst können XML-Elemente einbetten.
  • Der Wegfall von XML und imperativer UI-Programmierung reduziert Abstimmungsaufwand und erhöht die Konsistenz. Dadurch sinkt die Zahl potenzieller Probleme. Ein kleiner zusätzlicher Vorteil sind oft kürzere Build-Zeiten und eine etwas geringere App-Größe.

Nachteile

  • Immer mehr Entwickler beschäftigen sich mit der Bibliothek und sehen ihr Potenzial. Trotzdem basieren die meisten bestehenden Systeme weiterhin auf klassischen Android-Werkzeugen und lassen sich nicht von heute auf morgen vollständig umstellen.
  • Weil Jetpack Compose zum Zeitpunkt des Artikels noch in aktiver Entwicklung war, wurden manche Komponenten noch nicht unterstützt und einzelne Features waren nicht stabil. Die neue Art, Oberflächen zu beschreiben, bedeutet außerdem, dass auch neue Testansätze gelernt werden müssen. Das ist nachvollziehbar, verursacht aber zusätzlichen Lern- und Rechercheaufwand.
  • Wichtig ist außerdem, dass man neue Tools, Bibliotheken und Architekturen kontinuierlich im Blick behalten muss. Mit jeder Weiterentwicklung des Systems ändern sich Versionen, was wiederum regelmäßige Code-Anpassungen und Refactorings nach sich ziehen kann.

Was sind die Vor- und Nachteile von Jetpack Compose?

Zu den größten Vorteilen zählen weniger Boilerplate, eine sehr gute Kotlin-Integration und eine moderne, klar strukturierte UI-Architektur. Nachteile liegen vor allem im zusätzlichen Lernaufwand und in der Notwendigkeit, sich auf laufende Änderungen im Ökosystem einzustellen.

Fazit

Wie die Entwickler bei Google sinngemäß sagten: „Ihr habt uns schon lange darum gebeten - und wir haben es für euch umgesetzt.“ Jetpack Compose ist ein leistungsfähiges, modernes und zugleich intuitives Werkzeug zur Erstellung von Benutzeroberflächen, mit dem sich typische Routineaufgaben deutlich schneller umsetzen lassen. Durch integrierte Unterstützung für Material Design, Dark Theme und Animationen eröffnet Compose neue Möglichkeiten, schöne und benutzerfreundliche Apps zu entwickeln.

Ich möchte außerdem betonen, dass ich immer offen für Diskussionen zum Thema bin. Falls ihr Wünsche für weitere Themen habt, die ihr auf unserem Blog sehen möchtet, schreibt uns einfach.

FAQ

Jetpack Compose ist Googles modernes deklaratives UI-Toolkit für native Android-Oberflächen. Es reduziert Boilerplate, arbeitet direkt mit Kotlin und vereinfacht viele typische UI-Aufgaben im Vergleich zu klassischen Android Views.

Bei der imperativen Entwicklung wird die Oberfläche manuell aktualisiert. Bei der deklarativen Entwicklung beschreibt man dagegen, wie die UI für einen bestimmten Zustand aussehen soll, und das Framework übernimmt die Aktualisierung.

Zu den Vorteilen zählen weniger Boilerplate, gute Kotlin-Integration und eine moderne Architektur. Nachteile sind die noch laufende Entwicklung mancher Komponenten, zusätzlicher Lernaufwand und regelmäßige Anpassungen durch neue Versionen.

Igor Gridin

Igor Gridin

Mit über 15 Jahren Erfahrung in der Softwareentwicklung mit Java und Kotlin unterstütze ich im Banken- und Logistik-Bereich unsere Kunden bei spannenden nativen Android-Projekten. Hier schreibe ich über alle neuen Technologien und Trends, die im Bereich der Android-Anwendungsentwicklung auftauchen.

Verwandte Artikel

Spracheingabe erleichtert Dokumentation - ein Hackathon-Thema
Spracheingabe erleichtert Dokumentation - ein Hackathon-Thema

Spracheingabe macht es möglich, gegessene und getrunkene Lebensmittel intuitiv zu erfassen, ohne ständig auf ein Gerät schauen oder tippen zu müssen. Statt alles mühsam per Hand einzugeben, können Nutzer Mahlzeiten und Snacks einfach per Sprache dokumentieren. Das spart Zeit und senkt die Hürde für eine regelmäßige Erfassung.

Animationen in Jetpack Compose
Animationen in Jetpack Compose

Moderne Anwendungen werden immer stärker design- und damit nutzerzentriert gedacht. Für Nutzer ist die technische Umsetzung selten interessant - sie wird vielmehr vorausgesetzt. Ansprechendes Design, Animationen und eine gute Bedienbarkeit können dagegen einen echten Unterschied machen.

Wie man die VersionCode-Beschränkung von Xamarin.Android umgeht

Erfahre, warum dein Xamarin.Android-Build mit "Error executing task Aapt: VersionCode is outside 0, 65535 interval" fehlschlägt und wie du dieses Problem umgehen kannst.