Coil ist eine Bibliothek zum Laden von Bildern auf Android, geschrieben in Kotlin und basierend auf Koroutinen. Laut offizieller Dokumentation unterstützt die Bibliothek Memory Cache, Disk Cache und hardwarebeschleunigte Transformationen. Coil zeichnet sich durch seine minimale APK-Größe (etwa 150 KB) und vollständige Kompatibilität mit Jetpack Compose aus.
Wichtige Erkenntnisse
Coil (Coroutine Image Loader) ist eine Bildladebibliothek für Android, vollständig in Kotlin geschrieben und verwendet Koroutinen für asynchrone Operationen. Sie bietet eine einheitliche API zum Laden von Bitmap-Bildern aus dem Netzwerk, Ressourcen, Dateisystem und Content Provider mit automatischem mehrstufigem Caching.
Im Gegensatz zu Glide und Picasso verwendet Coil Kotlin Coroutines anstelle von Callback-Ketten, was den Code linearer und vorhersagbarer macht. Alle Lade- und Dekodierungsvorgänge werden über den Dispatcher Dispatchers.IO im Hintergrund ausgeführt, und die Ergebnisse werden ohne explizite Umschaltung an den Hauptthread geliefert.
Coil unterstützt Transformationen (Round, Blur, Grayscale), Übergangsanimationen, SVG und GIF sowie benutzerdefinierte Targets für nicht standardgemäße Anzeige. Laut Google I/O 2023 wird Coil in offiziellen Jetpack Compose-Tutorials neben Glide empfohlen.
ImageLoader ist die Hauptkomponente von Coil, verantwortlich für die Ausführung von Ladeanfragen und die Verwaltung des Caches. Jede Instanz enthält Verweise auf MemoryCache, DiskCache, BitmapPool und einen Koroutinen-Pool. Standardmäßig wird ein Singleton verwendet, der über Coil.imageLoader(context) erstellt wird.
ImageRequest ist ein Objekt, das eine einzelne Bildladeanfrage beschreibt: Datenquelle (URL, URI, Int-Ressource), Ziel-ImageView oder Target, Transformationen, Cache-Einstellungen und Platzhalter. ImageRequest wird über einen Builder erstellt, was Flexibilität und Lesbarkeit gewährleistet.
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()
Nach der Erstellung wird ImageRequest über enqueue oder execute an ImageLoader übergeben. Die enqueue-Methode startet eine Koroutine und gibt ein Disposable zurück, das ein Abbrechen des Ladens beim Verlassen des Bildschirms ermöglicht. Die execute-Methode ist eine Suspend-Funktion, die direkt ein Result zurückgibt.
ImageLoader überprüft nacheinander MemoryCache, DiskCache und führt nur bei Fehlschlag beider eine Netzwerkanfrage über HttpEngine aus. Nach dem Laden werden die Bytes unter Berücksichtigung der Zielgröße in ein Bitmap dekodiert, Transformationen angewendet, das Ergebnis in beiden Caches gespeichert und an das Target übergeben.
Coil ist auf einer Komponentenarchitektur aufgebaut, bei der jeder Teil über Dependency Injection ausgetauscht werden kann. Alle Komponenten werden in ImageLoaderFactory registriert und über den Builder an den ImageLoader-Konstruktor übergeben.
ImageLoader ist der Einstiegspunkt für alle Ladevorgänge. Jede Instanz enthält einen Koroutinen-Pool, BitmapPool, MemoryCache, DiskCache und eine Liste von Interceptoren. Standardmäßig wird eine globale Instanz erstellt, aber für Unit-Tests können separate Instanzen mit isolierten Caches erstellt werden.
MemoryCache ist ein arbeitsspeicherbasierter LRU-Cache (Least Recently Used), der dekodierte Bitmap-Objekte speichert. Die standardmäßige maximale Größe beträgt 25 % des verfügbaren Anwendungsspeichers, jedoch nicht weniger als 32 MB. Der Cache-Schlüssel wird aus URL + Größe + Transformationen gebildet, was das Abrufen veralteter Bilder verhindert.
DiskCache ist ein dateibasierter Cache für Rohdaten (JPEG, PNG, WebP) und dekodierte Metadaten. Er befindet sich im Cache-Verzeichnis der Anwendung und unterstützt die automatische Bereinigung bei Überschreitung des Limits. Plattenoperationen werden über DiskCache.Builder mit Verzeichnis- und Maximalgrößenkonfiguration durchgeführt.
Coil implementiert eine mehrstufige Caching-Strategie, die Netzwerkanfragen minimiert und die Bildanzeige beschleunigt. Jede Ebene hat ihren eigenen Zweck und ihre eigene Datenlebensdauer.
| Ebene | Speichertyp | Lebensdauer | Standardgröße |
|---|---|---|---|
| Memory Cache | Bitmap im RAM | Bis LRU-Verdrängung | 25 % des Heaps, ab 32 MB |
| Disk Cache | JPEG/WebP-Dateien | Bis Limitüberschreitung | 250 MB |
| Http Cache | OkHttp-Antworten | Gemäß Cache-Control-Headern | Abhängig vom HTTP-Client |
Memory Cache bietet sofortigen Zugriff auf bereits dekodierte Bitmaps. Disk Cache stellt sicher, dass die App nach dem ersten Laden ohne Netzwerk (Offline-First) funktioniert. Http Cache auf OkHttp-Ebene verarbeitet bedingte Anfragen mit ETag und If-Modified-Since.
Cache-Richtlinien werden pro Anfrage über CachePolicy mit drei Werten konfiguriert: ENABLED, READ_ONLY, WRITE_ONLY, DISABLED. Für Benutzeravatare kann beispielsweise READ_ONLY für Memory Cache und ENABLED für Disk Cache eingestellt werden.
Coil bietet je nach Anwendungsarchitektur mehrere Integrationsmethoden. Betrachten wir drei wichtige Szenarien mit funktionierenden Codebeispielen.
load ist eine Erweiterungsfunktion für ImageView, die einfachste Möglichkeit, ein Bild in einer Zeile zu laden. Die Funktion akzeptiert eine URL, URI, Int-Ressource oder Datei sowie alle optionalen Parameter über einen Lambda-Konfigurator.
imageView.load("https://example.com/photo.jpg") {
crossfade(true)
placeholder(R.drawable.placeholder)
error(R.drawable.error)
size(300, 300)
transformations(CircleCropTransformation())
}
Die load-Methode gibt ein Disposable zurück, das in onDestroy oder bei Wiederverwendung der View abgebrochen werden kann. Dies verhindert Speicherlecks und unnötige Netzwerkanfragen beim schnellen Scrollen von Listen.
AsyncImage ist eine composable Funktion zum Laden von Bildern in deklarativer UI. Sie akzeptiert jede Datenquelle und drei optionale Parameter für Zustände: Platzhalter, Fehler und Erfolg.
@Composable
fun NetworkImage(url: String) {
AsyncImage(
model = url,
contentDescription = "Netzwerkbild",
placeholder = ColorPainter(Color.Gray),
error = ColorPainter(Color.Red)
)
}
SubcomposeAsyncImage ist eine flexiblere Version, die die Anpassung der Anzeige während des Ladens über einen Inhaltsslot ermöglicht. Dies ist nützlich für Skelette (Shimmer) und Fortschrittsbalken.
Wenn ImageView oder AsyncImage nicht geeignet sind, können Sie ein Target mit einer einzigen onSuccess-Methode implementieren, die ein Bitmap akzeptiert. Dies wird zum Laden in Notification, RemoteViews oder OpenGL-Texturen verwendet.
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()
)
Die Wahl der Bildladebibliothek hängt von den Projektanforderungen ab. Coil konkurriert mit Glide und Picasso, die jeweils ihre Stärken haben. Ein Vergleich der wichtigsten Eigenschaften ist in der Tabelle dargestellt.
| Eigenschaft | Coil | Glide | Picasso |
|---|---|---|---|
| Sprache | Kotlin (100 %) | Java + Kotlin | Java |
| APK-Größe | ~150 KB | ~500 KB | ~120 KB |
| Koroutinen | Integriert | Nein (Callbacks) | Nein (Callbacks) |
| Jetpack Compose | Native Unterstützung | Über Accompanist | Drittanbieter |
| GIF/WebP | Ja (integriert) | Ja (integriert) | Nein |
| Google-Empfehlung | Ja (I/O 2023) | Ja | Nein |
Für neue Projekte mit Kotlin und Jetpack Compose wird Coil dank null zusätzlicher Koroutinen-Abhängigkeiten und minimaler Größe zur natürlichen Wahl. Glide bleibt für komplexe Szenarien mit Animationen und Videovorschauen bevorzugt. Picasso ist beiden in der Funktionalität unterlegen, gewinnt aber an Einfachheit.
Das Hinzufügen von Coil zu einem Android-Projekt erfolgt über eine Gradle-Abhängigkeit. Nach dem Hinzufügen registriert die Bibliothek automatisch einen ImageLoader über ContentProvider, sodass keine manuelle Initialisierung in Application erforderlich ist. Bei Bedarf wird über den Builder ein benutzerdefinierter ImageLoader erstellt.
// build.gradle.kts (app module)
dependencies {
implementation("io.coil-kt:coil:2.6.0")
// Für Jetpack Compose zusätzlich:
implementation("io.coil-kt:coil-compose:2.6.0")
// Für SVG-Unterstützung:
implementation("io.coil-kt:coil-svg:2.6.0")
// Für GIF-Unterstützung:
implementation("io.coil-kt:coil-gif:2.6.0")
}
Zur Anpassung von ImageLoader wird ImageLoaderFactory verwendet — ein Singleton, das in Application.onCreate erstellt wird. In der Fabrik können Cache-Grenzen, HTTP-Client, benutzerdefinierte Decoder und Protokollierung konfiguriert werden. Standardmäßig verwendet Coil OkHttp mit einem fertigen Verbindungspool.
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()
}
}
Häufig gestellte Fragen
Coil ist eine Bildladebibliothek für Android, geschrieben in Kotlin unter Verwendung von Koroutinen. Sie wird zum asynchronen Laden, Cachen und Anzeigen von Bitmap-Bildern aus dem Netzwerk, Ressourcen oder Dateisystem verwendet.
Coil ist zu 100 % in Kotlin geschrieben und verwendet Koroutinen anstelle des Callback-Mechanismus von Glide. Coil hat eine kleinere APK-Größe (~150 KB vs. ~500 KB) und native Jetpack Compose-Unterstützung über AsyncImage.
Fügen Sie die Abhängigkeit io.coil-kt:coil:2.6.0 zu build.gradle.kts hinzu. Für Jetpack Compose fügen Sie auch io.coil-kt:coil-compose:2.6.0 hinzu. Die Bibliothek registriert automatisch einen ImageLoader über ContentProvider.
Coil unterstützt JPEG, PNG, WebP, BMP, SVG (über das coil-svg-Modul) und GIF (über das coil-gif-Modul). AVIF- und HEIF-Formate werden über einen benutzerdefinierten Decoder auf Geräten mit Android 10+ unterstützt.
Der Cache wird über ImageLoader.Builder konfiguriert: memoryCache mit Angabe des Heap-Prozentsatzes, diskCache mit Pfad und Limit in Bytes. Cache-Richtlinien (ENABLED, DISABLED, READ_ONLY) werden pro Anfrage über CachePolicy konfiguriert.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch