CompositionLocal – Werte durch den Compose-Baum reichen, ohne sie durchzuschleifen
Wenn ein Wert durch acht Composables durchgereicht wird, nur damit ihn das neunte benutzen kann, ist etwas schief. CompositionLocal löst das – aber nur für eine sehr bestimmte Sorte von Werten.
Kennst du diese Sorte Parameter? Er wird ganz oben erzeugt, dann durch HomeScreen, Inhalt, KartenListe, Karte und KartenFuss durchgereicht — und erst dort wirklich gebraucht. Alle Zwischenstationen tragen ihn nur mit. In Compose heißt das prop drilling, und es gibt ein Werkzeug dagegen.
Der Aufbau
// 1) Ein Typ, den du weiterreichen willst
data class Markenfarben(val akzent: Color, val warnung: Color)
// 2) Der Kanal – mit einem Standardwert, falls niemand etwas gesetzt hat
val LocalMarke = staticCompositionLocalOf {
Markenfarben(akzent = Color(0xFF0F766E), warnung = Color(0xFFB91C1C))
}Ganz oben füllst du ihn einmal:
@Composable
fun App(marke: Markenfarben) {
CompositionLocalProvider(LocalMarke provides marke) {
HomeScreen() // reicht nichts weiter
}
}Und irgendwo tief unten holst du ihn dir:
@Composable
fun KartenFuss() {
val marke = LocalMarke.current
Text("Mehr erfahren", color = marke.akzent)
}Kein Parameter mehr in HomeScreen, Inhalt, KartenListe und Karte. Genau das war das Ziel.
staticCompositionLocalOf oder compositionLocalOf?
Der Unterschied ist die Sorte Wert, die du transportierst:
staticCompositionLocalOf— für Werte, die sich praktisch nie ändern (Theme, Marke, ein Logger). Ändert sich der Wert doch, wird der gesamte Inhalt darunter neu gebaut. Dafür kostet das Lesen im Normalbetrieb gar nichts.compositionLocalOf— für Werte, die sich durchaus ändern. Compose merkt sich dann, wer den Wert wirklich liest, und baut nur diese Stellen neu.
Faustregel: Ändert sich der Wert seltener als einmal pro Bildschirm-Leben, nimm static.
Wofür ich es benutze – und wofür nicht
Compose selbst nutzt genau dieses Werkzeug für MaterialTheme, LocalContext, LocalDensity und LocalConfiguration. Das ist auch die Sorte Wert, für die es gedacht ist: Umgebung, nicht Daten.
Was ich dort nicht hineinlege:
- Den Zustand eines Bildschirms. Der gehört ins ViewModel und wird bewusst als Parameter übergeben.
- Alles, wovon ich möchte, dass man es beim Lesen der Funktionssignatur sieht.
CompositionLocalmacht Abhängigkeiten unsichtbar — das ist der Preis für die Bequemlichkeit.
Ein Composable, das nur seine Parameter benutzt, kann ich isoliert testen und in einer @Preview anzeigen. Eins, das heimlich fünf CompositionLocals liest, nicht mehr ohne Weiteres. Deshalb: sparsam einsetzen, und wenn, dann für Dinge, die wirklich „die Umgebung" sind.
Du planst eine App mit eigenem Markenlook über viele Screens hinweg? Genau dafür ist das gebaut. Schreib mir, wenn du dabei Unterstützung brauchst.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
AnimatedVisibility in Jetpack Compose – ein- und ausblenden, das nicht springt
Ein Element einfach mit if wegzulassen, poppt hart weg. AnimatedVisibility blendet es weich ein und aus – mit sinnvollen Voreinstellungen und, wenn du willst, deiner eigenen Kombination aus Faden und Bewegung. Ich zeige dir beides.
snapshotFlow in Jetpack Compose – aus Compose-Zustand einen Flow machen
Manchmal willst du auf einen Compose-Zustand reagieren wie auf einen Datenstrom – entprellen, kombinieren, sammeln. Genau das macht snapshotFlow. Ich zeige dir das an der häufigsten Aufgabe: mehr laden, wenn der Nutzer ans Listenende scrollt.
kotlinx.serialization: JSON und data class ohne Handarbeit verbinden
Eine API antwortet mit JSON, deine App will eine data class. Dazwischen steht in vielen Projekten ein handgeschriebener Parser. Mit kotlinx.serialization sind es eine Annotation und eine Zeile – und ein Schalter, ohne den deine App beim nächsten API-Update abstürzt.