Kako zamijeniti AsyncTask s Kotlin Coroutines

Još uvijek koristite AsyncTask u svojim Android aplikacijama? Vjerojatno više ne bi trebao biti. Evo kako ih zamijeniti Kotlinovim korutinama.

Dugo vremena u Androidu, ako ste morali nešto učiniti asinkrono prilikom izrade aplikacije, vjerojatno biste koristili AsyncTask. AsyncTask je API u okviru Androida koji olakšava (ish) pokretanje operacija u pozadini i vraćanje vrijednosti kada se završe. I to ima smisla. Za razliku od Kotlin Coroutines, AsyncTask postoji već neko vrijeme i odmah je ugrađen.

Međutim, i filozofija dizajna i implementacija AsyncTask-a postali su donekle zastarjeli tijekom godina. Zbog toga Google ima obustavio AsyncTask API. I dalje ga možete koristiti ako želite, ali Google to ne preporučuje. Srećom, postoji cijela hrpa alternativa AsyncTasku, uključujući značajku Kotlin jezika — korutine.

Kotlinov API za korutine nevjerojatno je moćan okvir koji vam omogućuje da radite hrpu stvari. Ovaj članak samo će zagrebati površinu onoga što je moguće. Proći ćemo kroz osnove potrebne za migraciju s AsyncTask na korutine.

Dodavanje podrške Coroutines

Prije nego počnete koristiti korutine, morate ih zapravo dodati svom projektu.

Dodavanje podrške za Kotlin

Ako ste već implementirali Kotlin, prijeđite na sljedeći odjeljak. U suprotnom, morat ćete dodati podršku za Kotlin svom projektu. Za više detalja pogledajte moj vodič o dodavanju Kotlina u postojeći projekt.

Dodavanje knjižnica Coroutine

Na razini vašeg modula build.gradle, uključuju sljedeće ovisnosti.

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

Sinkronizirajte svoj projekt i Kotlinove korutine sada će biti dostupne za korištenje.

Korištenje korutina

Implementacija CoroutineScope

Kako biste koristili korutine, morat ćete imati dostupnu instancu CoroutineScope. Jednostavan način da to učinite je da ga jednostavno implementirate u svoju klasu koja sadrži.

Na primjer, za implementaciju CoroutineScope u aktivnost:

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

override fun onDestroy(){
super.onDestroy()

cancel()
}
}

Ovo će učiniti da SomeActivity implementira sučelje CoroutineScope putem klase MainScope. MainScope će upravljati svom logikom implementacije za CoroutineScope, dok vam omogućuje korištenje metoda CoroutineScope. zovem cancel() u onDestroy() osigurava da se nijedna asinkrona logika ne nastavi izvoditi nakon što aktivnost izađe.

Zamjena AsyncTask s Coroutines

Recimo da imate AsyncTask unutar aktivnosti koja izvodi dugotrajnu operaciju u pozadini i na kraju vraća niz. Nešto poput sljedećeg.

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
}
}

Lako je zamijeniti ovo korutinom. Samo koristite async() metoda. Kotlinova async() radi na bilo kojoj niti na kojoj je pokrenut, ali radi to asinkrono. To znači da možete ažurirati Views i slično bez brige o korištenju prave Niti.

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"
}
}
}

Kao što vidite, korištenje korutina može biti puno jednostavnije od korištenja AsyncTask. Ne morate samo nazvati async() i neka ipak učini svoje. Možete zadržati referencu na njega i čak čekati da završi.

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()

Vraćanje vrijednosti s asinkrom

Možete čak vratiti vrijednost iz async() ako želiš. Tako bi izvorni primjer mogao postati nešto poput ovoga.

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
}
}

Korištenje withContext

Radi praktičnosti, Kotlin pruža withContext(). Ovo uključuje cjelinu await() stvar i samo vam vraća vrijednost.

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
}
}

Zaključak

Gore navedeni primjeri samo su neke osnovne upotrebe Kotlinovih korutina za početak. Ne morate ograničiti korutine na aktivnosti ili čak bilo što s odgovarajućim životnim ciklusom. Možete ih izvoditi praktično bilo gdje. Postoje i naprednije operacije, poput odabira niti koja bi trebala pokretati asinkronu logiku. Ovaj vodič uglavnom služi za pokazivanje kako zamijeniti jednostavan AsyncTask jednostavnom korutinom.

Za više pojedinosti o tome kako rade korutine i kako možete koristiti njihove naprednije značajke, pogledajte službena Kotlin dokumentacija.