Coil — είναι μια βιβλιοθήκη για φόρτωση εικόνων στο Android, γραμμένη σε Kotlin και βασισμένη σε κορουτίνες. Σύμφωνα με την επίσημη τεκμηρίωση, η βιβλιοθήκη υποστηρίζει Memory Cache, Disk Cache και μετασχηματισμούς με επιτάχυνση υλικού. Coil ξεχωρίζει για το ελάχιστο μέγεθος APK (περίπου 150 KB) και την πλήρη συμβατότητα με το Jetpack Compose.
Κύρια σημεία
Coil (Coroutine Image Loader) — είναι μια βιβλιοθήκη για φόρτωση εικόνων στο Android, γραμμένη εξ ολοκλήρου σε Kotlin και χρησιμοποιώντας κορουτίνες για ασύγχρονη λειτουργία. Παρέχει ένα ενοποιημένο API για φόρτωση εικόνων bitmap από το δίκτυο, πόρους, σύστημα αρχείων και Content Provider, με αυτόματη προσωρινή αποθήκευση σε πολλαπλά επίπεδα.
Σε αντίθεση με τα Glide και Picasso, το Coil χρησιμοποιεί Kotlin Coroutines αντί για αλυσίδες callback, καθιστώντας τον κώδικα πιο γραμμικό και προβλέψιμο. Όλες οι λειτουργίες φόρτωσης και αποκωδικοποίησης εκτελούνται σε νήματα παρασκηνίου μέσω του Dispatchers.IO, και το αποτέλεσμα παραδίδεται στο κύριο νήμα χωρίς ρητή εναλλαγή.
Το Coil υποστηρίζει μετασχηματισμούς (Round, Blur, Grayscale), κινούμενα σχέδια μετάβασης, SVG και GIF, καθώς και προσαρμοσμένο Target για μη τυπική εμφάνιση. Σύμφωνα με το Google I/O 2023, το Coil συνιστάται στα επίσημα σεμινάρια Jetpack Compose μαζί με το Glide.
ImageLoader — το κύριο στοιχείο του Coil, υπεύθυνο για την εκτέλεση αιτημάτων φόρτωσης και τη διαχείριση της προσωρινής μνήμης. Κάθε στιγμιότυπο περιέχει αναφορές σε MemoryCache, DiskCache, BitmapPool και μια δεξαμενή κορουτινών. Από προεπιλογή χρησιμοποιείται ένα singleton που δημιουργείται μέσω Coil.imageLoader(context).
ImageRequest — ένα αντικείμενο που περιγράφει ένα αίτημα φόρτωσης εικόνας: πηγή δεδομένων (URL, URI, πόρος Int), προορισμός ImageView ή Target, μετασχηματισμοί, ρυθμίσεις προσωρινής αποθήκευσης και placeholder. Το ImageRequest δημιουργείται μέσω builder, προσφέροντας ευελιξία και αναγνωσιμότητα.
val request = ImageRequest.Builder(context)
.data("https://example.com/image.jpg")
.crossfade(true)
.size(512, 512)
.transformations(listOf(RoundedCornersTransformation(12f)))
.memoryCachePolicy(CachePolicy.ENABLED)
.diskCachePolicy(CachePolicy.ENABLED)
.target(imageView)
.build()
Μετά τη δημιουργία, το ImageRequest μεταβιβάζεται στο ImageLoader μέσω enqueue ή execute. Η μέθοδος enqueue εκκινεί μια κορουτίνα και επιστρέφει ένα Disposable, επιτρέποντας την ακύρωση της φόρτωσης κατά την έξοδο από την οθόνη. Η μέθοδος execute είναι μια συνάρτηση suspend που επιστρέφει απευθείας Result.
Το ImageLoader ελέγχει διαδοχικά το MemoryCache, το DiskCache και μόνο σε περίπτωση αποτυχίας και των δύο εκτελεί ένα αίτημα δικτύου μέσω HttpEngine. Μετά τη φόρτωση, τα bytes αποκωδικοποιούνται σε Bitmap λαμβάνοντας υπόψη το μέγεθος-στόχο, εφαρμόζονται μετασχηματισμοί, το αποτέλεσμα αποθηκεύεται και στις δύο προσωρινές μνήμες και μεταβιβάζεται στο Target.
Το Coil είναι χτισμένο σε αρχιτεκτονική στοιχείων με δυνατότητα αντικατάστασης οποιουδήποτε μέρους μέσω Dependency Injection. Όλα τα στοιχεία καταχωρούνται στο ImageLoaderFactory και μεταβιβάζονται στον κατασκευαστή του ImageLoader μέσω builder.
ImageLoader — το σημείο εισόδου για όλες τις λειτουργίες φόρτωσης. Κάθε στιγμιότυπο περιέχει μια δεξαμενή κορουτινών, BitmapPool, MemoryCache, DiskCache και μια λίστα αναχαιτιστών. Από προεπιλογή δημιουργείται ένα καθολικό στιγμιότυπο, αλλά για αρθρωτό έλεγχο μπορούν να δημιουργηθούν ξεχωριστά στιγμιότυπα με απομονωμένη προσωρινή μνήμη.
MemoryCache — προσωρινή μνήμη εντός RAM βασισμένη σε LRU (Least Recently Used) που αποθηκεύει αποκωδικοποιημένα αντικείμενα Bitmap. Το προεπιλεγμένο μέγιστο μέγεθος είναι 25% της διαθέσιμης μνήμης της εφαρμογής, αλλά όχι λιγότερο από 32 MB. Το κλειδί προσωρινής μνήμης σχηματίζεται από URL + μέγεθος + μετασχηματισμούς, αποκλείοντας την παροχή μη ενημερωμένης εικόνας.
DiskCache — προσωρινή μνήμη αρχείων για ακατέργαστα δεδομένα (JPEG, PNG, WebP) και αποκωδικοποιημένα μεταδεδομένα. Βρίσκεται στον κατάλογο προσωρινής μνήμης της εφαρμογής και υποστηρίζει αυτόματο καθαρισμό όταν ξεπεραστεί το όριο. Η εργασία με το δίσκο εκτελείται μέσω DiskCache.Builder με ρύθμιση καταλόγου και μέγιστου μεγέθους.
Coil υλοποιεί μια πολυεπίπεδη στρατηγική προσωρινής αποθήκευσης που ελαχιστοποιεί τα αιτήματα δικτύου και επιταχύνει την εμφάνιση εικόνων. Κάθε επίπεδο έχει το δικό του σκοπό και διάρκεια ζωής δεδομένων.
| Επίπεδο | Τύπος αποθήκευσης | Διάρκεια ζωής | Προεπιλεγμένο μέγεθος |
|---|---|---|---|
| Memory Cache | Bitmap στη μνήμη | Μέχρι αντικατάσταση LRU | 25% heap, από 32 MB |
| Disk Cache | Αρχεία JPEG/WebP | Μέχρι υπέρβαση ορίου | 250 MB |
| Http Cache | Απαντήσεις OkHttp | Σύμφωνα με κεφαλίδες Cache-Control | Εξαρτάται από τον πελάτη HTTP |
Το Memory Cache παρέχει άμεση πρόσβαση σε ήδη αποκωδικοποιημένα bitmap. Το Disk Cache εγγυάται τη λειτουργία της εφαρμογής χωρίς δίκτυο (offline-first) μετά την πρώτη φόρτωση. Http Cache στο επίπεδο OkHttp επεξεργάζεται αιτήματα υπό όρους ETag και If-Modified-Since.
Οι πολιτικές προσωρινής αποθήκευσης διαμορφώνονται ανά αίτημα μέσω CachePolicy με τρεις τιμές: ENABLED, READ_ONLY, WRITE_ONLY, DISABLED. Για παράδειγμα, για τα avatar χρηστών μπορεί να οριστεί READ_ONLY για Memory Cache και ENABLED για Disk Cache.
Το Coil προσφέρει διάφορους τρόπους ενσωμάτωσης ανάλογα με την αρχιτεκτονική της εφαρμογής. Ας εξετάσουμε τρία βασικά σενάρια με λειτουργικά παραδείγματα κώδικα.
load — συνάρτηση επέκτασης για ImageView, ο απλούστερος τρόπος φόρτωσης εικόνας σε μία γραμμή. Η συνάρτηση δέχεται URL, URI, πόρο Int ή File και όλες τις προαιρετικές παραμέτρους μέσω ενός ρυθμιστή lambda.
imageView.load("https://example.com/photo.jpg") {
crossfade(true)
placeholder(R.drawable.placeholder)
error(R.drawable.error)
size(300, 300)
transformations(CircleCropTransformation())
}
Η μέθοδος load επιστρέφει ένα Disposable που μπορεί να ακυρωθεί στο onDestroy ή κατά την επαναχρησιμοποίηση του View. Αυτό αποτρέπει διαρροές μνήμης και περιττά αιτήματα δικτύου κατά τη γρήγορη κύλιση λίστας.
AsyncImage — συνάρτηση composable για φόρτωση εικόνων σε δηλωτικό UI. Δέχεται οποιαδήποτε πηγή δεδομένων και τρεις προαιρετικές παραμέτρους για καταστάσεις: placeholder, error και success.
@Composable
fun NetworkImage(url: String) {
AsyncImage(
model = url,
contentDescription = "εικόνα δικτύου",
placeholder = ColorPainter(Color.Gray),
error = ColorPainter(Color.Red)
)
}
SubcomposeAsyncImage — μια πιο ευέλικτη έκδοση που επιτρέπει την προσαρμογή της εμφάνισης κατά τη φόρτωση μέσω μιας υποδοχής περιεχομένου. Αυτό είναι χρήσιμο για σκελετούς (shimmer) και γραμμές προόδου.
Εάν το ImageView ή το AsyncImage δεν είναι κατάλληλα, μπορεί να υλοποιηθεί Target με μία μόνο μέθοδο onSuccess που δέχεται Bitmap. Αυτό χρησιμοποιείται για φόρτωση σε Notification, RemoteViews ή υφή OpenGL.
val target = object : BitmapTarget() {
override fun onSuccess(result: Bitmap) {
notificationRemoteView.setImageViewBitmap(R.id.icon, result)
}
}
imageLoader.enqueue(
ImageRequest.Builder(context)
.data(url)
.target(target)
.build()
)
Η επιλογή βιβλιοθήκης για φόρτωση εικόνων εξαρτάται από τις απαιτήσεις του έργου. Coil ανταγωνίζεται τα Glide και Picasso, καθένα από τα οποία έχει τα δυνατά του σημεία. Η σύγκριση των κύριων χαρακτηριστικών παρουσιάζεται στον πίνακα.
| Χαρακτηριστικό | Coil | Glide | Picasso |
|---|---|---|---|
| Γλώσσα | Kotlin (100%) | Java + Kotlin | Java |
| Μέγεθος APK | ~150 KB | ~500 KB | ~120 KB |
| Κορουτίνες | Ενσωματωμένες | Όχι (callback) | Όχι (callback) |
| Jetpack Compose | Εγγενής υποστήριξη | Μέσω Accompaniment | Τρίτου μέρους |
| GIF/WebP | Ναι (ενσωματωμένο) | Ναι (ενσωματωμένο) | Όχι |
| Σύσταση Google | Ναι (I/O 2023) | Ναι | Όχι |
Για νέα έργα σε Kotlin και Jetpack Compose, το Coil γίνεται η φυσική επιλογή χάρη στη μηδενική πρόσθετη εξάρτηση από κορουτίνες και το ελάχιστο μέγεθος. Το Glide παραμένει προτιμότερο για σύνθετα σενάρια με κινούμενα σχέδια και προεπισκοπήσεις βίντεο. Το Picasso υστερεί και των δύο σε λειτουργικότητα, αλλά κερδίζει σε απλότητα.
Η σύνδεση του Coil με ένα έργο Android γίνεται μέσω εξάρτησης Gradle. Μετά την προσθήκη, η βιβλιοθήκη καταχωρεί αυτόματα το ImageLoader μέσω ContentProvider, επομένως δεν απαιτείται χειροκίνητη αρχικοποίηση στο Application. Εάν χρειάζεται προσαρμογή, δημιουργείται δικό σας ImageLoader μέσω builder.
// build.gradle.kts (μονάδα εφαρμογής)
dependencies {
implementation("io.coil-kt:coil:2.6.0")
// Επιπλέον για Jetpack Compose:
implementation("io.coil-kt:coil-compose:2.6.0")
// Για υποστήριξη SVG:
implementation("io.coil-kt:coil-svg:2.6.0")
// Για υποστήριξη GIF:
implementation("io.coil-kt:coil-gif:2.6.0")
}
Για την προσαρμογή του ImageLoader χρησιμοποιείται ImageLoaderFactory — ένα singleton που δημιουργείται στο Application.onCreate. Στο εργοστάσιο μπορούν να ρυθμιστούν όρια προσωρινής μνήμης, πελάτης HTTP, προσαρμοσμένοι αποκωδικοποιητές και καταγραφή. Από προεπιλογή το Coil χρησιμοποιεί OkHttp με έτοιμη δεξαμενή συνδέσεων.
class App : Application(), ImageLoaderFactory {
override fun newImageLoader(): ImageLoader {
return ImageLoader.Builder(this)
.memoryCache {
MemoryCache.Builder()
.maxSizePercent(0.25)
.build()
}
.diskCache {
DiskCache.Builder()
.directory(cacheDir.resolve("coil_cache"))
.maxSizeBytes(512 * 1024 * 1024)
.build()
}
.build()
}
}
Συχνές ερωτήσεις
Coil — βιβλιοθήκη για φόρτωση εικόνων στο Android, γραμμένη σε Kotlin με χρήση κορουτινών. Χρησιμοποιείται για ασύγχρονη φόρτωση, προσωρινή αποθήκευση και εμφάνιση εικόνων bitmap από το δίκτυο, πόρους ή σύστημα αρχείων.
Το Coil είναι γραμμένο 100% σε Kotlin και χρησιμοποιεί κορουτίνες αντί για τον μηχανισμό callback στο Glide. Το Coil έχει μικρότερο μέγεθος APK (~150 KB έναντι ~500 KB) και εγγενή υποστήριξη για Jetpack Compose μέσω AsyncImage.
Προσθέστε την εξάρτηση io.coil-kt:coil:2.6.0 στο build.gradle.kts. Για Jetpack Compose προσθέστε επίσης io.coil-kt:coil-compose:2.6.0. Η βιβλιοθήκη καταχωρεί αυτόματα το ImageLoader μέσω ContentProvider.
Coil υποστηρίζει JPEG, PNG, WebP, BMP, SVG (μέσω της μονάδας coil-svg) και GIF (μέσω της μονάδας coil-gif). Οι μορφές AVIF και HEIF υποστηρίζονται μέσω προσαρμοσμένου αποκωδικοποιητή σε συσκευές με Android 10+.
Η προσωρινή μνήμη ρυθμίζεται μέσω ImageLoader.Builder: memoryCache με καθορισμό ποσοστού του heap, diskCache με διαδρομή και όριο σε bytes. Οι πολιτικές προσωρινής μνήμης (ENABLED, DISABLED, READ_ONLY) ρυθμίζονται ανά αίτημα μέσω CachePolicy.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης