jambit ToiletPaper 112

Kotlin Coroutinen

Problem

Bestimmte Aktionen sollen im Hintergrund ausgeführt werden, um den Main-Thread der App nicht zu blockieren. Typischerweise werden dafür Threads oder AsyncTasks verwendet: Die Aktion wird im Background ausgeführt und schließlich wird das Ergebnis auf dem Main-Thread dargestellt.

Lösung

Kotlin bietet einen etwas eleganteren Weg mit Coroutinen an. Coroutinen sind leichtgewichtige Threads, die auf einen von Kotlin verwalteten Thread-Pool dispatched werden, sofern man vorhandene Dispatcher verwendet. Vergleichbar ist das Ganze mit GCD von iOS.

Beispiel

Ein Image soll heruntergeladen und dargestellt werden:

private fun downloadImageWithCoroutines() {
    GlobalScope.launch(Dispatchers.Main) {
        binding.status.text = "Downloading image ..."
        // Download the image on an IO dispatcher without blocking the main thread
        val image = withContext(Dispatchers.IO) { downloadImage() }
        // Continue on the main thread
        binding.image.setImageDrawable(image)
    }
}

Zunächst wird im oberen Beispiel auf dem Main-Thread der Status gesetzt, anschließend erfolgt ein asynchroner Download des Images. Die Besonderheit dabei ist, dass der Main-Thread nicht blockiert wird, sondern erst, wenn das Ergebnis verfügbar ist, läuft der restliche Code auf dem Main-Thread weiter.

Technisch wird das von Kotlin so gelöst, dass der Code nach dem withContext als Continuation ausgeführt wird. Man könnte die downloadImage Methode also so umschreiben, dass diese das Ergebnis einer Continuation übergibt und nicht direkt zurückliefert. Natürlich muss sich hier der Aufrufer der Methode um das entsprechende Threading kümmern:

private fun downloadImage(continuation: (Drawable?) -> Unit) {
    val drawable = url.openStream()?.use {
        Drawable.createFromStream(it, "image")
    }
    continuation(drawable)
}

Eine besondere Stärke ist die Kombination mehrerer async Calls. Die async-Calls können hier gleichzeitig auf unterschiedlichen IO-Threads ausgeführt werden:

// Start multiple requests
val image1 = async(Dispatchers.IO) { downloadImage1() }
val image2 = async(Dispatchers.IO) { downloadImage2() }
// Wait for the results and show the images
binding.image1.setImageDrawable(image1.await())
binding.image2.setImageDrawable(image2.await())

Weiterführende Aspekte

---

Autor: Marco Pfattner / Senior Software Architect/ Business Division Automotive Bavaria

Zum Toilet Paper #112: Kotlin Coroutinen (pdf)

Kotlin Coroutines jambit ToiletPaper

Cookie-Einstellungen

Diese Website verwendet Cookies, um Inhalte und Anzeigen zu personalisieren, Funktionen für soziale Medien anbieten zu können und Zugriffe auf die Website zu analysieren. Zudem werden Informationen zu Ihrer Verwendung der Website an Partner für soziale Medien, Werbung und Analysen weitergegeben. Die Partner führen diese Informationen möglicherweise mit weiteren Daten zusammen, die Sie ihnen bereitgestellt haben oder die sie im Rahmen Ihrer Nutzung der Dienste gesammelt haben.

Weitere Informationen finden Sie in unserer Datenschutzerklärung. Dort können Sie nachträglich auch Ihre Cookie-Einstellungen ändern.

contact icon

Kontakt aufnehmen