Το σχόλιο @Composable — θεμελιώδες στοιχείο του Jetpack Compose που μετατρέπει μια συνηθισμένη συνάρτηση Kotlin σε ένα δηλωτικό δομικό στοιχείο διεπαφής χρήστη. Χωρίς αυτό το σχόλιο, καμία οθόνη δεν μπορεί να δημιουργηθεί στη σύγχρονη ανάπτυξη Android. Σύμφωνα με Google Android Developers, 2026, πάνω από 80% των νέων έργων σε Kotlin χρησιμοποιούν Compose για τη δημιουργία UI, και το @Composable είναι το συχνότερα χρησιμοποιούμενο σχόλιο στο οικοσύστημα.
Κύρια
@Composable — είναι ένα σχόλιο της γλώσσας Kotlin που σημειώνει μια συνάρτηση ως προορισμένη για την περιγραφή της διεπαφής χρήστη στο πλαίσιο Jetpack Compose. Όταν ο μεταγλωττιστής Kotlin συναντά αυτό το σχόλιο, δημιουργεί επιπλέον κώδικα που επιτρέπει στη συνάρτηση να λειτουργεί στο πλαίσιο σύνθεσης — το σύστημα διαχείρισης δέντρου UI.
Το σχόλιο @Composable εισήχθη από τη Google το 2021 μαζί με την πρώτη σταθερή έκδοση Jetpack Compose 1.0. Πριν από την εμφάνισή του, η ανάπτυξη διεπαφών για Android γινόταν αποκλειστικά μέσω σημάνσεων XML και του συστήματος View. Το @Composable άλλαξε ριζικά την προσέγγιση: αντί να περιγράφεται το UI σε ένα ξεχωριστό αρχείο σημάνσεων, ο προγραμματιστής γράφει τη διεπαφή απευθείας σε Kotlin.
Η κύρια διαφορά μεταξύ @Composable και συνηθισμένων συναρτήσεων Kotlin — η ικανότητα να διαβάζει και να αντιδρά σε αλλαγές κατάστασης. Όταν μια μεταβλητή που διαβάζει μια συνάρτηση Composable αλλάζει τιμή, το σύστημα προγραμματίζει αυτόματα την επανεκκίνηση (ανασύνθεση) αυτής της συνάρτησης. Αυτό απαλλάσσει τον προγραμματιστή από τη χειροκίνητη ενημέρωση UI μέσω findViewById και setText.
Η εσωτερική μηχανική του @Composable βασίζεται στην έννοια του slot — μιας ειδικής περιοχής μνήμης που διατίθεται για κάθε συνάρτηση στη σύνθεση. Σε αυτό το slot αποθηκεύονται οι τιμές που μεταβιβάζονται στη συνάρτηση, καθώς και οι πληροφορίες υπηρεσίας που απαιτούνται για σύγκριση σε επόμενες κλήσεις.
Για να δηλώσετε μια συνάρτηση Composable, αρκεί να προσθέσετε το σχόλιο @Composable πριν από τη λέξη-κλειδί fun. Η συνάρτηση πρέπει να βρίσκεται σε ένα πακέτο που εισάγει το σχόλιο από το androidx.compose.runtime. Το όνομα της συνάρτησης συνιστάται να γράφεται με κεφαλαίο γράμμα — αυτή είναι μια γενικά αποδεκτή σύμβαση στην κοινότητα Compose που διαχωρίζει οπτικά τα στοιχεία UI από τις συνηθισμένες συναρτήσεις.
import androidx.compose.runtime.Composable
@Composable
fun Greeting(name: String) {
var count by remember { mutableStateOf(0) }
Column {
Text("Γεια, $name!")
Button(onClick = { count++ }) {
Text("Πατήθηκε $count φορές")
}
}
}
Οι παράμετροι μιας συνάρτησης Composable μπορούν να είναι οτιδήποτε — αρχικοί τύποι, συμβολοσειρές, λάμβδα και ακόμη άλλες συναρτήσεις Composable που μεταβιβάζονται μέσω Slot API. Συνιστάται να κάνετε τις παραμέτρους αμετάβλητες (val) για να αποφύγετε παρενέργειες κατά την ανασύνθεση. Όλα τα μεταβλητά δεδομένα πρέπει να διαχειρίζονται μέσω μηχανισμών κατάστασης του Compose.
Οι συναρτήσεις Composable δεν μπορούν να επιστρέψουν οποιαδήποτε τιμή όπως οι συνηθισμένες συναρτήσεις — μοναδική τους αποστολή είναι η δημιουργία ή ενημέρωση ενός τμήματος του δέντρου UI. Υπάρχουν ωστόσο ειδικά μοτίβα όπως το State Hoisting, στο οποίο η συνάρτηση Compose λαμβάνει κατάσταση και callbacks μέσω παραμέτρων, παραμένοντας αγνή και επαναχρησιμοποιήσιμη.
Το σύστημα Compose επιβάλλει αρκετά αυστηρούς περιορισμούς στον τρόπο με τον οποίο οι συναρτήσεις Composable πρέπει να εμφανίζονται και να συμπεριφέρονται. Πρώτος κανόνας: μια συνάρτηση Composable μπορεί να καλεί μόνο άλλες συναρτήσεις Composable ή συνηθισμένες συναρτήσεις χωρίς παρενέργειες. Αυτό εξασφαλίζει την προβλεψιμότητα της σύνθεσης και τη σωστή λειτουργία των βελτιστοποιήσεων Compose.
Ο δεύτερος κανόνας αφορά τη σειρά εκτέλεσης. Το Compose έχει το δικαίωμα να καλεί συναρτήσεις Composable σε οποιαδήποτε σειρά, επομένως ο κώδικας στο σώμα μιας τέτοιας συνάρτησης δεν πρέπει να βασίζεται στη σειρά κλήσης των γειτονικών συναρτήσεων. Κάθε συνάρτηση Composable πρέπει να είναι αυτοδύναμη στο επίπεδο της θέσης της στο δέντρο UI.
Τρίτος κανόνας — απαγόρευση παρενεργειών μέσα στο σώμα της συνάρτησης Composable. Λειτουργίες όπως εγγραφή σε βάση δεδομένων, αποστολή δικτυακών αιτημάτων ή τροποποίηση εξωτερικών μεταβλητών πρέπει να εκτελούνται μόνο μέσα σε ειδικά εφέ LaunchedEffect, DisposableEffect ή SideEffect. Η παραβίαση αυτού του κανόνα οδηγεί σε απρόβλεπτη συμπεριφορά κατά τις ανασυνθέσεις.
Τέταρτος κανόνας: Οι συναρτήσεις Composable πρέπει να είναι αδύναμες (idempotent). Η επαναλαμβανόμενη κλήση με τα ίδια ορίσματα πρέπει να παράγει το ίδιο UI. Αυτή η απαίτηση είναι απαραίτητη για τη σωστή λειτουργία της βελτιστοποίησης skipping, κατά την οποία το Compose παραλείπει την επανασχεδίαση συναρτήσεων των οποίων τα δεδομένα εισόδου δεν έχουν αλλάξει.
// Σωστό: καθαρή συνάρτηση Composable χωρίς παρενέργειες
@Composable
fun UserCard(user: User, onClick: () -> Unit) {
Card(modifier = Modifier.clickable { onClick() }) {
Text(text = user.name)
}
}
// Λάθος: παρενέργεια μέσα στο σώμα
@Composable
fun WrongCard(userId: String) {
// val result = viewModel.loadUser(userId) // ΔΕΝ ΕΠΙΤΡΕΠΕΤΑΙ
Text("Φόρτωση...")
}
Ας δούμε ένα πρακτικό παράδειγμα δημιουργίας οθόνης προφίλ χρησιμοποιώντας το σχόλιο @Composable. Εδώ επιδεικνύουμε το συνδυασμό πολλών συναρτήσεων Composable, την εργασία με κατάσταση και τροποποιητές — βασικά στοιχεία κάθε διάταξης Compose.
@Composable
fun ProfileScreen(userId: String) {
var isFollowed by remember { mutableStateOf(false) }
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
ProfileHeader(userId = userId)
Spacer(modifier = Modifier.height(16.dp))
StatsRow(posts = 42, followers = 1280)
Spacer(modifier = Modifier.height(24.dp))
FollowButton(
isFollowed = isFollowed,
onToggle = { isFollowed = !isFollowed }
)
}
}
@Composable
fun ProfileHeader(userId: String) {
Row(verticalAlignment = Alignment.CenterVertically) {
AsyncImage(model = "https://example.com/avatars/$userId",
contentDescription = "User avatar")
Spacer(modifier = Modifier.width(12.dp))
Text(text = "Χρήστης #$userId", style = MaterialTheme.typography.headlineMedium)
}
}
@Composable
fun StatsRow(posts: Int, followers: Int) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
StatItem("Posts", posts)
StatItem("Followers", followers)
}
}
@Composable
fun StatItem(label: String, value: Int) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "$value", style = MaterialTheme.typography.headlineSmall)
Text(text = label, style = MaterialTheme.typography.bodySmall)
}
}
Στο παράδειγμα, κάθε συνάρτηση Composable είναι υπεύθυνη για το δικό της μέρος της οθόνης: το ProfileScreen διαχειρίζεται τη γενική κατάσταση και σύνθεση των θυγατρικών συναρτήσεων, το ProfileHeader εμφανίζει το avatar και το όνομα, και το StatsRow — το μπλοκ με στατιστικά. Αυτή η προσέγγιση ακολουθεί την αρχή της μεμονωμένης ευθύνης και απλοποιεί την επαναχρησιμοποίηση στοιχείων.
Στο Jetpack Compose υπάρχουν τρεις κύριοι τύποι συναρτήσεων Composable. Ο πρώτος τύπος — δοχεία (Row, Column, Box, LazyColumn) που καθορίζουν τη διάταξη των θυγατρικών στοιχείων. Ο δεύτερος — στοιχεία εμφάνισης (Text, Image, Icon, Button) που αποδίδουν συγκεκριμένα στοιχεία UI. Ο τρίτος — προσαρμοσμένες συναρτήσεις Composable που συνδυάζουν ενσωματωμένα στοιχεία σε επαναχρησιμοποιήσιμα μπλοκ.
Τα δοχεία διαφέρουν από τα συνηθισμένα στοιχεία καθώς δέχονται μια λάμβδα content — την τελευταία παράμετρο τύπου @Composable () -> Unit. Ακριβώς αυτός ο μηχανισμός επιτρέπει τη δημιουργία ένθετων δέντρων UI: κάθε δοχείο δημιουργεί μια θυγατρική σύνθεση με το δικό της πλαίσιο και περιοχή μνήμης.
Οι προσαρμοσμένες συναρτήσεις Composable χωρίζονται σε δύο υποτύπους: έξυπνες (smart) και απλές (dumb). Οι έξυπνες συναρτήσεις διαχειρίζονται κατάσταση και λογική — περιέχουν κλήσεις σε remember, LaunchedEffect και άλλα API Compose. Οι απλές συναρτήσεις λαμβάνουν όλα τα δεδομένα μέσω παραμέτρων και απλώς τα εμφανίζουν. Η διαίρεση σε έξυπνα και απλά στοιχεία βελτιώνει τη δοκιμασιμότητα και την επαναχρησιμοποίηση κώδικα.
| Τύπος | Παράδειγμα | Ρόλος |
|---|---|---|
| Δοχείο | Column, Row, Box | Διαχείριση διάταξης θυγατρικών στοιχείων |
| Στοιχείο | Text, Image, Button | Εμφάνιση περιεχομένου και επεξεργασία εισόδου |
| Προσαρμοσμένο | ProfileCard, UserList | Συνδυασμός τυπικών στοιχείων |
Το κύριο πλεονέκτημα του σχολίου @Composable — η δυνατότητα δημιουργίας επαναχρησιμοποιήσιμων στοιχείων UI χωρίς κληρονομικότητα και περίπλοκες ιεραρχίες κλάσεων. Σε αντίθεση με το σύστημα View, όπου κάθε προσαρμοσμένο στοιχείο απαιτούσε τη δημιουργία μιας κλάσης Java με κατασκευαστές, ένα στοιχείο Composable είναι απλώς μια συνάρτηση Kotlin με παραμέτρους.
Για την εξασφάλιση της επαναχρησιμοποίησης, εφαρμόζεται το μοτίβο Slot API, όπου η συνάρτηση Composable δέχεται content λάμβδας για διαφορετικές περιοχές της διάταξής της. Για παράδειγμα, το στοιχείο Card μπορεί να δέχεται ξεχωριστό content για την κεφαλίδα, το σώμα και το κάτω μέρος, καθιστώντας το καθολικό για οποιαδήποτε οθόνη εφαρμογής.
Οι τροποποιητές (Modifier) παίζουν κεντρικό ρόλο στην επαναχρησιμοποίηση: επιτρέπουν τη ρύθμιση αποστάσεων, μεγεθών, κλικ και κινήσεων χωρίς να τροποποιείται το ίδιο το στοιχείο. Συνιστάται να μεταβιβάζετε πάντα το Modifier ως παράμετρο της συνάρτησης Composable με προκαθορισμένη τιμή: Modifier = Modifier — αυτή είναι η τυπική πρακτική που έχει υιοθετηθεί στις επίσημες βιβλιοθήκες της Google.
@Composable
fun SectionCard(
modifier: Modifier = Modifier,
title: String,
content: @Composable () -> Unit
) {
Card(modifier = modifier) {
Column(modifier = Modifier.padding(16.dp)) {
Text(text = title, style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(8.dp))
content()
}
}
}
Χάρη στο Slot API, το στοιχείο SectionCard μπορεί να χρησιμοποιηθεί σε διαφορετικές οθόνες με διαφορετικό περιεχόμενο — φόρμες, λίστες, μπλοκ κειμένου. Ο συνδυασμός τροποποιητών και Slot API καθιστά τα στοιχεία Compose μέγιστα ευέλικτα χωρίς να χάνουν την ασφάλεια τύπου που παρέχει το Kotlin.
Συχνές Ερωτήσεις
Μια συνάρτηση @Composable εκτελείται στο πλαίσιο σύνθεσης και μπορεί να διαβάσει κατάσταση, επανεκκινούμενη αυτόματα όταν αυτή αλλάζει. Οι συνηθισμένες συναρτήσεις Kotlin δεν έχουν πρόσβαση σε μηχανισμούς παρακολούθησης κατάστασης και δεν συμμετέχουν στην κατασκευή του δέντρου UI.
Όχι, οι συναρτήσεις Composable μπορούν να κληθούν μόνο από άλλες συναρτήσεις Composable, καθώς απαιτείται ειδικό πλαίσιο σύνθεσης. Για την ενσωμάτωση κώδικα Compose με συνηθισμένο Kotlin, χρησιμοποιείται η μέθοδος setContent { } στο Activity ή ComposeView στο σύστημα View.
Αυτή είναι μια σύμβαση ονομασίας που έχει υιοθετηθεί στην κοινότητα Compose. Το κεφαλαίο διαχωρίζει οπτικά τα στοιχεία UI από τις συνηθισμένες συναρτήσεις, ακολουθώντας τους κανόνες ονομασίας κλάσεων. Δεν είναι απαίτηση του μεταγλωττιστή, αλλά συνιστώμενη πρακτική στην τεκμηρίωση της Google.
Δεν υπάρχει περιορισμός στον αριθμό. Στην πράξη, μια μεγάλη οθόνη μπορεί να περιέχει 50–100 συναρτήσεις Composable, συμπεριλαμβανομένων των ενσωματωμένων στοιχείων (Text, Button) και των προσαρμοσμένων. Το Compose βελτιστοποιεί το δέντρο συναρτήσεων και εκτελεί μόνο εκείνες των οποίων τα δεδομένα εισόδου έχουν αλλάξει.
Συνήθως οι συναρτήσεις Composable επιστρέφουν Unit, καθώς η δουλειά τους είναι η δημιουργία UI. Υπάρχουν ωστόσο εξειδικευμένες συναρτήσεις όπως το remember και το derivedStateOf που είναι σημειωμένες με @Composable και επιστρέφουν τιμές. Αυτό είναι εξαίρεση, όχι κανόνας.
Συμπεράσματα
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης