withContext(Dispatchers.IO) – schwere Arbeit vom Main-Thread nehmen
Datei lesen oder ein Bild dekodieren blockiert den Main-Thread und ruckelt die UI. Mit withContext(Dispatchers.IO) schiebst du blockierende Arbeit sauber auf einen Hintergrund-Thread.
Auf Android läuft die UI auf dem Main-Thread. Alles, was dort blockiert – eine Datei lesen, ein Bild dekodieren, eine langsame Berechnung – lässt die Oberfläche ruckeln oder friert sie im schlimmsten Fall ein (ANR). Die saubere Lösung mit Coroutines: withContext(Dispatchers.IO) schiebt genau diesen Teil auf einen Hintergrund-Thread und gibt das Ergebnis zurück.
Blockierende Arbeit auslagern
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class ThumbnailRepository(private val api: ApiService) {
// suspend-Funktion: der Aufrufer bleibt "main-safe",
// die blockierende Arbeit passiert auf einem IO-Thread.
suspend fun loadThumbnail(url: String): Bitmap = withContext(Dispatchers.IO) {
val bytes = api.download(url) // blockierend (Netzwerk/Datei)
BitmapFactory.decodeByteArray(bytes, 0, bytes.size) // blockierend (CPU/IO)
}
}Der Aufruf aus dem ViewModel bleibt schlank und main-sicher:
viewModelScope.launch {
val bitmap = repo.loadThumbnail(url) // wartet, ohne den Main-Thread zu blockieren
_thumbnail.value = bitmap
}Welchen Dispatcher wofür?
Dispatchers.IO– Netzwerk, Datei-/Datenbankzugriff, alles, was auf Ein-/Ausgabe wartet.Dispatchers.Default– reine CPU-Arbeit (Sortieren, Parsen großer Listen, Bildfilter).Dispatchers.Main– UI-Updates; hier landet der Code nachwithContextautomatisch wieder.
Zwei Dinge, die du dir merken solltest
withContextgibt einen Wert zurück – anders alslaunch. Das Ergebnis der letzten Zeile ist der Rückgabewert.- Retrofit und Room sind schon main-safe. Deren
suspend-Funktionen wechseln intern selbst den Thread – die musst du nicht zusätzlich inwithContext(Dispatchers.IO)wickeln. Der Wrapper ist für deinen eigenen blockierenden Code.
Wenn du eine flüssige Android-App in Kotlin & Compose brauchst – ohne Ruckler und ANRs – sprich mich an.
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
Room-Migrationen – das Schema ändern, ohne Nutzerdaten zu verlieren
Eine neue Spalte in der Entity, und beim nächsten Start ist der Spielstand weg – weil fallbackToDestructiveMigration die Datenbank einfach löscht. So machst du es richtig, inklusive Test.
stateIn und shareIn – aus einem kalten Flow wird geteilter Zustand
Jeder Sammler eines kalten Flows startet die Arbeit neu – zwei Beobachter, zwei Datenbankabfragen. stateIn und shareIn machen daraus einen Strom, den sich alle teilen, samt aktuellem Wert und Abschalten bei Inaktivität.
viewModelScope – Coroutinen, die mit dem Bildschirm verschwinden
Eine Coroutine, die nach dem Schließen des Bildschirms weiterläuft, schreibt in ein ViewModel, das niemand mehr sieht – und hält im schlimmsten Fall die ganze Activity im Speicher. viewModelScope beendet sie automatisch.