Вы все еще используете AsyncTask в своих приложениях для Android? Тебе, наверное, больше не следует быть. Вот как заменить их сопрограммами Kotlin.
В течение долгого времени в Android, если вам нужно было сделать что-то асинхронно при создании приложения, вы, вероятно, использовали AsyncTask. AsyncTask — это API в платформе Android, который позволяет легко (почти) запускать операции в фоновом режиме и возвращать значения по завершении. И это имеет смысл. В отличие от сопрограмм Kotlin, AsyncTask существует уже некоторое время и уже встроен.
Однако и философия проектирования, и реализация AsyncTask с годами несколько устарели. По этой причине у Google есть устарел API AsyncTask. Вы все равно можете использовать его, если хотите, но Google не рекомендует этого делать. К счастью, существует целая куча альтернатив AsyncTask, включая особенность языка Kotlin — сопрограммы.
API сопрограмм Kotlin — это невероятно мощный фреймворк, который позволяет вам делать множество вещей. Эта статья лишь поверхностно коснется того, что возможно. Мы рассмотрим основы, необходимые для перехода от AsyncTask к сопрограммам.
Добавление поддержки сопрограмм
Прежде чем вы сможете начать использовать сопрограммы, вам необходимо добавить их в свой проект.
Добавление поддержки Kotlin
Если у вас уже реализован Kotlin, перейдите к следующему разделу. В противном случае вам придется добавить поддержку Kotlin в свой проект. Для получения более подробной информации ознакомьтесь с моим руководством по добавлению Kotlin в существующий проект.
Добавление библиотек сопрограмм
На уровне вашего модуля build.gradle
, включите следующие зависимости.
dependencies {
...
implementation 'org.jetbrains.kotlinx: kotlinx-coroutines-core: 1.5.0'
implementation 'org.jetbrains.kotlinx: kotlinx-coroutines-android: 1.5.0'
}
Синхронизируйте свой проект, и сопрограммы Kotlin теперь будут доступны для использования.
Использование сопрограмм
Реализация CoroutineScope
Чтобы использовать сопрограммы, вам понадобится экземпляр CoroutineScope. Самый простой способ сделать это — просто реализовать его в содержащем классе.
Например, чтобы реализовать CoroutineScope в действии:
classSomeActivity : AppCompatActivity, CoroutineScope by MainScope() {
...
override fun onDestroy(){
super.onDestroy()
cancel()
}
}
Это заставит SomeActivity реализовать интерфейс CoroutineScope посредством класса MainScope. MainScope будет обрабатывать всю логику реализации CoroutineScope, позволяя вам использовать методы CoroutineScope. Вызов cancel()
в onDestroy()
гарантирует, что асинхронная логика не будет продолжать работать после завершения действия.
Замена AsyncTask сопрограммами
Предположим, у вас есть AsyncTask внутри Activity, который выполняет длительную операцию в фоновом режиме и в конечном итоге возвращает строку. Что-то вроде следующего.
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
}
}
Заменить это сопрограммой легко. Просто используйте async()
метод. Котлин async()
выполняется в любом потоке, в котором он был запущен, но делает это асинхронно. Это означает, что вы можете обновлять представления и тому подобное, не беспокоясь об использовании правильного потока.
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"
}
}
}
Как видите, использование сопрограмм может быть намного проще, чем использование AsyncTask. Вам не нужно просто позвонить async()
и пусть оно делает свое дело. Вы можете сохранить ссылку на него и даже дождаться его завершения.
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()
Возврат значений с помощью async
Вы даже можете вернуть значение из async()
если ты хочешь. Итак, исходный пример мог бы выглядеть примерно так.
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
}
}
Использование withContext
Для удобства Котлин предоставляет withContext()
. Это встраивает весь await()
вещь и просто возвращает вам значение.
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
}
}
Заключение
Приведенные выше примеры — это всего лишь базовое использование сопрограмм Kotlin для начала. Вам не нужно ограничивать сопрограммы действиями или даже чем-то еще с правильным жизненным циклом. Вы можете запустить их практически где угодно. Существуют также более сложные операции, такие как выбор потока, который должен выполнять асинхронную логику. Это руководство в основном предназначено для того, чтобы показать, как заменить простую AsyncTask простой сопрограммой.
Более подробную информацию о том, как работают сопрограммы и как можно использовать их более продвинутые функции, см. официальная документация Котлина.