Composable Function — är den grundläggande enheten för användargränssnittet i Jetpack Compose, som avgör hur en del av skärmen ska se ut och bete sig. Varje sådan funktion är markerad med @Composable-annoteringen och körs i ett speciellt sammanhang, vilket låter Compose spåra beroenden och automatiskt bygga om UI när data ändras. Enligt Google Android Developers, 2026, påverkar korrekt konstruktion av Composable-funktioner direkt applikationens prestanda och effektiviteten av recomposition.
Huvudpunkter
Composable Function — är en funktion i programmeringsspråket Kotlin markerad med @Composable-annoteringen, som beskriver en del av användargränssnittet på ett deklarativt sätt. Istället för att skapa och konfigurera View-objekt via Java-kod eller XML-uppmärkning, skriver utvecklaren helt enkelt hur UI ska se ut vid varje datatillstånd.
Huvudskillnaden mellan en Composable-funktion och det traditionella Android View-systemet ligger i uppdateringsmodellen. I det klassiska tillvägagångssättet anropade utvecklaren manuellt findViewById, ändrade text via setText, hanterade synlighet via setVisibility. Composable Function befriar från denna rutin: när data ändras bestämmer systemet självt vilka funktioner som måste startas om och utför endast dem.
Kotlin-kompilatorn, när den bearbetar @Composable-annoteringen, genererar extra kod som integrerar funktionen i kompositionsmekanismen. Denna kod inkluderar läsning och skrivning till slots — speciella minnesceller som lagrar tillstånd och parametrar för varje Composable-funktion i det aktuella UI-trädet. Tack vare denna integration vet Compose vilka funktioner som är beroende av vilka data.
Syntaxen för en Composable-funktion är extremt koncis: lägg bara till @Composable före nyckelordet fun. Funktionen kan acceptera vilka parametrar som helst, inkludera andra Composable-anrop i sin kropp och använda Kotlin-konstruktioner — villkor, loopar, when-uttryck — för villkorlig visning av UI.
@Composable
fun ProductItem(
product: Product,
modifier: Modifier = Modifier,
onAddToCart: () -> Unit
) {
Card(modifier = modifier.padding(8.dp)) {
Row(modifier = Modifier.fillMaxWidth().padding(12.dp),
verticalAlignment = Alignment.CenterVertically) {
Column(modifier = Modifier.weight(1f)) {
Text(text = product.name, style = MaterialTheme.typography.titleMedium)
Text(text = "${product.price}", color = MaterialTheme.colorScheme.primary)
}
Button(onClick = onAddToCart) {
Text("Lägg i varukorgen")
}
}
}
}
I detta exempel accepterar Composable-funktionen ProductItem ett Product-objekt, en modifierare och en callback. Alla tre parametrar är oföränderliga, vilket garanterar förutsägbart beteende vid recomposition. Modifieraren skickas som en parameter med ett standardvärde — detta är en standardpraxis som tillåter den anropande parten att anpassa marginaler och storlekar.
Inuti en Composable-funktion används inbyggda Material Design-komponenter (Text, Button, Card, TextField) eller grundläggande primitiver (Canvas, Layout). Varje komponent accepterar parametrar för att konfigurera utseende och beteende, samt en eller flera modifierare via modifier-parametern.
Modifierare (Modifier) — är en kedja av funktioner som ändrar storlek, position, händelsehantering och utseende hos en komponent. Ordningen på modifierare i kedjan har betydelse: clickable.semantics fungerar annorlunda än semantics.clickable, och padding.background färgar bakgrunden av området inklusive padding, vilket är kritiskt vid design.
Inuti en Composable-funktion kan if- och when-villkor användas för villkorlig visning av UI-delar, samt for-loopar för dynamiska listor. Alla dessa konstruktioner fungerar naturligt, eftersom Kotlin är ett fullfjädrat programmeringsspråk. Det är dock viktigt att komma ihåg: om villkoret eller loopen innehåller anrop till Composable-funktioner deltar de också i recomposition.
@Composable
fun ProductList(
products: List<Product>,
modifier: Modifier = Modifier
) {
LazyColumn(modifier = modifier) {
items(products, key = { it.id }) { product ->
ProductItem(
product = product,
onAddToCart = { /* add to cart */ }
)
}
}
}
Låt oss titta på ett exempel på en produktsökningsskärm med flera Composable-funktioner. Här visas typiska mönster: inmatningsfält med tillstånd, filtrering av lista, hantering av tomt resultat och laddning.
data class Product(
val id: String,
val name: String,
val price: Double,
val category: String
)
@Composable
fun SearchScreen() {
var query by remember { mutableStateOf("") }
val products = remember(query) { getFilteredProducts(query) }
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
OutlinedTextField(
value = query,
onValueChange = { query = it },
label = { Text("Sök produkter") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
when (products) {
is Loading -> CircularProgressIndicator()
is Empty -> Text("Inga resultat hittades")
is Result -> LazyColumn {
items(products.items, key = { it.id }) { product ->
ProductItem(product = product, onAddToCart = {})
}
}
}
}
}
Detta exempel demonstrerar flera idiom samtidigt: remember för att spara sökfrågans tillstånd, remember(query) för filtrering med nyckel, when för tre UI-tillstånd och LazyColumn för effektiv listvisning. Vart och ett av dessa idiom är resultatet av praktisk erfarenhet av att utveckla Compose-applikationer.
Composable-funktioner accepterar parametrar precis som vanliga Kotlin-funktioner, men med en viktig skillnad: parametern kan vara en annan Composable-funktion som skickas via en lambda med @Composable-annotering. Denna mekanism kallas Slot API och är det huvudsakliga mönstret för att skapa återanvändbara behållare.
Slot API löser problemet som i det traditionella View-systemet löstes via ViewGroup och programmatisk tillägg av barn-Viewer. Istället för addView-metoder använder Compose content-lambdas — den sista parametern med typen @Composable () -> Unit. Den anropande parten skickar vilket UI som helst till denna lambda, och behållaren själv bestämmer endast dess placering.
Parametrar för en Composable-funktion kan ha standardvärden, vilket förenklar deras användning i olika sammanhang. Det rekommenderas att göra endast de parametrar obligatoriska utan vilka funktionen inte kan utföra sin uppgift, och de övriga förse med rimliga standardvärden.
| Parameter | Typ | Exempel |
|---|---|---|
| Obligatorisk | Vilken typ som helst | name: String |
| Valfri | Med standardvärde | modifier: Modifier = Modifier |
| Content | @Composable () -> Unit | content: @Composable () -> Unit |
| Callback | Lambda utan @Composable | onClick: () -> Unit |
I Compose-gemenskapen har flera etablerade idiom bildats som gör Composable-funktioner mer läsbara och förutsägbara. Det första — State Hoisting: tillståndet lyfts till en högre nivå och Composable-funktionen får det via parametrar. Detta gör funktionen ren och återanvändbar i olika sammanhang.
Det andra idiomet — Event-driven parametrar. Istället för att skicka ViewModel eller useCase till Composable-funktionen skickas endast specifika callbacks: onSave, onDelete, onNavigateToDetail. Detta minskar koppling och förenklar testning — för att testa ProductItem behövs ingen ViewModel, endast en lambda-stub.
Det tredje idiomet — CompositionLocal för att skicka gemensam data genom kompositionsträdet. Tema, skärmdensitet, aktuell rutt — allt detta skickas via CompositionLocal, vilket undviker parameterkedjor genom dussintals Composable-funktioner. Man bör dock inte missbruka CompositionLocal: explicita parametrar är alltid att föredra framför implicita beroenden.
// State Hoisting: tillstånd lyft till föräldrafunktionen
@Composable
fun CounterDisplay(
count: Int,
onIncrement: () -> Unit
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "Räknare: $count", style = MaterialTheme.typography.headlineLarge)
Button(onClick = onIncrement) {
Text("+1")
}
}
}
// Användning med State Hoisting
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
CounterDisplay(
count = count,
onIncrement = { count++ }
)
}
Vanliga frågor
Ja, return är tillåtet, men med försiktighet. Compose optimerar recomposition på nivån av enskilda funktioner och en tidig return kan störa denna optimering. Det är bättre att använda villkorsoperatorer if eller when i funktionskroppen.
I Kotlin är Unit ett singleton-objekt, inte en tom typ. Composable-funktioner returnerar Unit, vilket tekniskt betyder att de returnerar själva Unit-objektet. I praktiken spelar detta dock ingen roll — returvärdet ignoreras av kompositionssystemet.
Att skicka föränderliga samlingar är möjligt, men det är dålig praxis. Om samlingen ändras kommer Compose inte att veta om det eftersom referensen till objektet förblir densamma. Använd immutable listor eller mutableStateListOf för spårbara ändringar.
För felsökning, använd Android Studio med Layout Inspector, som visar det aktuella trädet av Composable-funktioner, parametervärden och orsaker till recomposition. Den vanliga Kotlin-felsökaren fungerar också — brytpunkter inuti Composable-funktioner utlöses korrekt vid varje recomposition.
En Composable-funktion returnerar alltid Unit, därför anges inte return type. Ett försök att returnera en annan typ kommer att orsaka ett kompileringsfel, eftersom @Composable-annoteringen inte är kompatibel med returtyper som inte är Unit.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också