Hvordan erstatte AsyncTask med Kotlins Coroutines

Bruker du fortsatt AsyncTask i Android-appene dine? Det burde du nok ikke være lenger. Slik erstatter du dem med Kotlins Coroutines.

I veldig lang tid i Android, hvis du trengte å gjøre noe asynkront når du lager en app, ville du sannsynligvis brukt AsyncTask. AsyncTask er en API i Androids rammeverk som gjør det enkelt (ish) å kjøre operasjoner i bakgrunnen og returnere verdier når du er ferdig. Og det gir mening. I motsetning til Kotlins Coroutines, har AsyncTask eksistert en stund, og den er innebygd.

Imidlertid har både designfilosofien og implementeringen av AsyncTask blitt noe utdatert med årene. På grunn av det har Google avviklet AsyncTask API. Du kan fortsatt bruke den hvis du vil, men Google anbefaler ikke å gjøre det. Heldigvis finnes det en hel haug med alternativer til AsyncTask, inkludert en funksjon av Kotlin-språket - korutiner.

Kotlins coroutines API er et utrolig kraftig rammeverk som lar deg gjøre en hel haug med ting. Denne artikkelen kommer bare til å skrape i overflaten av hva som er mulig. Vi skal gå gjennom det grunnleggende som trengs for å migrere fra AsyncTask til coroutines.

Legger til Coroutines-støtte

Før du kan begynne å bruke koroutiner, må du faktisk legge dem til i prosjektet ditt.

Legger til Kotlin-støtte

Hvis du allerede har implementert Kotlin, hopper du videre til neste seksjon. Ellers må du legge til Kotlin-støtte til prosjektet ditt. Sjekk ut veiledningen min om å legge til Kotlin i et eksisterende prosjekt for mer informasjon.

Legger til Coroutine-biblioteker

På ditt modulnivå build.gradle, inkluderer følgende avhengigheter.

dependencies {
...
implementation 'org.jetbrains.kotlinx: kotlinx-coroutines-core: 1.5.0'
implementation 'org.jetbrains.kotlinx: kotlinx-coroutines-android: 1.5.0'
}

Synkroniser prosjektet ditt, og Kotlins koroutiner vil nå være tilgjengelige for bruk.

Bruker Coroutines

Implementering av et CoroutineScope

For å bruke coroutines, må du ha en CoroutineScope-instans tilgjengelig. En enkel måte å gjøre dette på er å bare implementere det i innholdsklassen din.

For eksempel, for å implementere et CoroutineScope i en aktivitet:

classSomeActivity : AppCompatActivity, CoroutineScope by MainScope() {
...

override fun onDestroy(){
super.onDestroy()

cancel()
}
}

Dette vil få SomeActivity til å implementere CoroutineScope-grensesnittet ved hjelp av MainScope-klassen. MainScope vil håndtere all implementeringslogikk for CoroutineScope, samtidig som du kan bruke CoroutineScope-metodene. Ringer cancel() i onDestroy() sørger for at ingen asynkron logikk fortsetter å kjøre etter at aktiviteten avsluttes.

Erstatter AsyncTask med Coroutines

La oss si at du har en AsyncTask inne i en aktivitet som utfører en langvarig operasjon i bakgrunnen og til slutt returnerer en streng. Noe sånt som følgende.

private inner classSomeTask : AsyncTask() {
override fun doInBackground(vararg params: Void): String {
try {
//Pretend this is an actual operation that takes 10 seconds and not just sleeping.
Thread.sleep(10000);
} catch (e: InterruptedException) {}

return"SomeString";
}

override fun onPostExecute(result: String) {
val someTextView = findViewById(R.id.some_text_view)
someTextView.text = result
}
}

Det er enkelt å erstatte dette med en coroutine. Bare bruk async() metode. Kotlins async() kjører på hvilken tråd den ble lansert på, men gjør det asynkront. Dette betyr at du kan oppdatere visninger og slikt uten å måtte bekymre deg for å bruke riktig tråd.

classSomeActivity : AppCompatActivity(), CoroutineScope by MainScope() {
...

private fun doOperation(){
async {
//Inside coroutine scopes (like inside async here), delay is used instead of Thread.sleep.
delay(10000)

val someTextView = findViewById(R.id.some_text_view)
someTextView.text = "SomeString"
}
}
}

Som du kan se, kan bruk av korutiner være mye enklere enn å bruke AsyncTask. Du trenger ikke bare ringe async() og la det gjøre sitt. Du kan holde en referanse til den og til og med vente til den er ferdig.

val asyncJob = async {
//Some operation
}
//Pause here until the async block is finished.
asyncJob.await()

//This won't run until asyncJob finishes, but other operations started before the job, or started from another method, can still run.
doSomethingElse()

Returnerer verdier med asynkron

Du kan til og med returnere en verdi fra async() hvis du vil. Så det originale eksemplet kan bli noe sånt som dette.

classSomeActivity : AppCompatActivity(), CoroutineScope by MainScope() {
...
private fun doOperation(){
val asyncJob = async {
//Inside coroutine scopes (like inside async here), delay is used instead of Thread.sleep.
delay(10000)

//Whatever the type is of the last line is what async() eventually returns.
"SomeString"
}

val result = asyncJob.await()

val someTextView = findViewById(R.id.some_text_view)
someTextView.text = result
}
}

Bruke withContext

For enkelhets skyld tilbyr Kotlin withContext(). Dette fletter inn helheten await() ting og returnerer bare verdien til deg.

classSomeActivity : AppCompatActivity(), CoroutineScope by MainScope() {
...
private fun doOperation(){
//Run asynchronously on the main Thread.
val result = withContext(Dispatchers.Main) {
delay(10000)

"SomeResult"
}

val someTextView = findViewById(R.id.some_text_view)
someTextView.text = result
}
}

Konklusjon

Eksemplene ovenfor er bare noen grunnleggende bruk av Kotlins koroutiner for å komme i gang. Du trenger ikke å begrense koroutiner til aktiviteter eller til og med noe med en riktig livssyklus. Du kan kjøre dem stort sett hvor som helst. Det er også mer avanserte operasjoner, som å velge hvilken tråd som skal kjøre den asynkrone logikken. Denne veiledningen er hovedsakelig for å vise hvordan du erstatter en enkel AsyncTask med en enkel coroutine.

For mer informasjon om hvordan coroutines fungerer, og hvordan du kan bruke de mer avanserte funksjonene deres, sjekk ut offisiell Kotlin-dokumentasjon.