Jak nahradit AsyncTask Kotlin's Coroutines

Stále používáte AsyncTask ve svých aplikacích pro Android? Už bys asi neměl být. Zde je návod, jak je nahradit Kotlinovými Coroutines.

Po velmi dlouhou dobu v Androidu, pokud byste při vytváření aplikace potřebovali něco dělat asynchronně, pravděpodobně byste používali AsyncTask. AsyncTask je API v rámci Androidu, které usnadňuje (ish) spouštění operací na pozadí a po dokončení vrací hodnoty. A to dává smysl. Na rozdíl od Kotlinových Coroutines existuje AsyncTask již nějakou dobu a je přímo zabudován.

Jak filozofie designu, tak implementace AsyncTask však v průběhu let poněkud zastaraly. Kvůli tomu má Google zastaralé rozhraní AsyncTask API. Pokud chcete, můžete jej stále používat, ale Google to nedoporučuje. Naštěstí existuje celá řada alternativ k AsyncTask, včetně funkce jazyka Kotlin — coroutines.

Kotlin's coroutines API je neuvěřitelně výkonný rámec, který vám umožní dělat spoustu věcí. Tento článek pouze načrtne povrch toho, co je možné. Projdeme si základy potřebné k migraci z AsyncTask na corutiny.

Přidání podpory Coroutines

Než budete moci začít používat corutiny, musíte je skutečně přidat do svého projektu.

Přidání podpory Kotlin

Pokud již máte Kotlin implementován, přeskočte na další sekci. V opačném případě budete muset do svého projektu přidat podporu Kotlin. Podívejte se na můj tutoriál o přidání Kotlina do existujícího projektu pro více podrobností.

Přidávání knihoven Coroutine

Na úrovni vašeho modulu build.gradle, zahrnují následující závislosti.

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

Synchronizujte svůj projekt a Kotlinovy ​​rutiny budou nyní k dispozici k použití.

Použití Coroutines

Implementace CoroutineScope

Abyste mohli používat coroutiny, musíte mít k dispozici instanci CoroutineScope. Snadný způsob, jak toho dosáhnout, je jednoduše implementovat do vaší třídy obsahující.

Chcete-li například implementovat CoroutineScope do aktivity:

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

override fun onDestroy(){
super.onDestroy()

cancel()
}
}

Díky tomu bude SomeActivity implementovat rozhraní CoroutineScope prostřednictvím třídy MainScope. MainScope zvládne veškerou implementační logiku pro CoroutineScope a zároveň vám umožní používat metody CoroutineScope. Povolání cancel() v onDestroy() zajišťuje, že po ukončení aktivity nebude pokračovat žádná asynchronní logika.

Nahrazení AsyncTask pomocí Coroutines

Řekněme, že máte v aktivitě AsyncTask, která na pozadí provádí dlouhotrvající operaci a nakonec vrátí řetězec. Něco jako následující.

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

Nahradit to coroutinem je snadné. Stačí použít async() metoda. Kotlinův async() běží na kterémkoli vláknu, na kterém byl spuštěn, ale provádí to asynchronně. To znamená, že můžete aktualizovat zobrazení a podobně, aniž byste se museli starat o použití správného vlákna.

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

Jak můžete vidět, použití coroutines může být mnohem jednodušší než použití AsyncTask. Nemusíte jen volat async() a ať si to udělá po svém. Můžete na něj podržet odkaz a dokonce počkat, až skončí.

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

Vrácení hodnot s async

Můžete dokonce vrátit hodnotu z async() jestli chceš. Takže z původního příkladu by se mohlo stát něco takového.

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

Použití withContext

Pro pohodlí poskytuje Kotlin withContext(). Toto vkládá celek await() věc a jen vám vrátí hodnotu.

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

Závěr

Výše uvedené příklady jsou jen základním využitím Kotlinových corutin, abyste mohli začít. Korutiny nemusíte omezovat na aktivity nebo dokonce na cokoli s řádným životním cyklem. Můžete je provozovat v podstatě kdekoli. Existují také pokročilejší operace, jako je výběr vlákna, které má spustit asynchronní logiku. Tato příručka je hlavně pro ukázku, jak nahradit jednoduchý AsyncTask jednoduchou korutinou.

Další podrobnosti o tom, jak fungují corutiny a jak můžete využít jejich pokročilejší funkce, najdete na oficiální dokumentace Kotlin.