Выполнить сложную задачу в фоновом потоке, вернуть результат в основном потоке - PullRequest
0 голосов
/ 27 марта 2019

Я потратил некоторое время, чтобы найти дружественное для разработчика решение (без добавления зависимостей в проект) о том, как выполнить некоторую сложную задачу в фоновом потоке, а после завершения задачи вернуть результат в основной поток.Я нашел "AsyncTask", который позволяет это сделать.Но чтобы использовать его, вам нужно написать шаблонный код для каждой задачи, которую нужно запустить в фоновом режиме.Я разработчик iOS, который решил попробовать разработку под Android.Так что в Swift вы можете просто использовать следующий код для выполнения этой задачи:

DispatchQueue.global().async(execute: {
      //Do some hard task in background
   DispatchQueue.main.async(execute: {
      //Return to main
   })
})

Это выглядит довольно просто.Но в Котлине я не нашел такого простого решения и решил его создать.

Вот что я сделал:

Я создал общий класс

import android.os.AsyncTask

class BaseAsyncTask<M>: AsyncTask<()->M, Int, M>() {

    var completion: ((M)->Unit)? = null

    override fun doInBackground(vararg params: (() -> M)?): M? {
        for (p in params) {
            return p?.invoke()
        }
        return  null
    }

    override fun onPostExecute(result: M) {
        super.onPostExecute(result)

        completion?.invoke(result)
    }
}

И менеджер

class AsyncManager {

    companion object {

        fun <M>execute(inBackground: ()->M, inMain: (M)->Unit): BaseAsyncTask<M> {
            val task = BaseAsyncTask<M>()
            task.completion = inMain
            task.execute(inBackground)

            return task
        }

        fun <M>execute(inBackground: ()->M): BaseAsyncTask<M> {
            val task = BaseAsyncTask<M>()
            task.execute(inBackground)

            return task
        }
    }

}

Теперь я использую это так:

AsyncManager.execute({
   //Do some hard task in background
}, {
  //Return to main
})

Выглядит как разработчик.

Log.e("MAIN", "MAIN THREAD SHOULD NOT BE BLOCKED")

AsyncManager.execute({
    Log.e("TASK", "Started background task")
    val retval = "The value from background"
    Thread.sleep(5000)
    Log.e("TASK", "Finished background task with result: " + retval)
    retval
}, {
    Log.e("TASK", "Started task in Main thread with result from Background: " + it)
})

Log.e("MAIN", "MAIN THREAD SHOULD NOT BE BLOCKED - 1")

И журнал:

2019-03-27 17: 11: 00.719 17082-17082 / com.test.testapp E / MAIN: ГЛАВНАЯ РЕЗЬБА НЕ ДОЛЖНА БЛОКИРОВАТЬ

2019-03-27 17: 11: 00.722 17082-17082 /com.test.testapp E / MAIN: ГЛАВНАЯ РЕЗЬБА НЕ ДОЛЖНА БЛОКИРОВАТЬСЯ - 1

2019-03-27 17: 11: 00.722 17082-17124 / com.test.testapp E / TASK: Запущена фоновая задача

2019-03-27 17: 11: 05.737 17082-17124 / com.test.testapp E / TASK: завершенная фоновая задача с результатом: значение из фона

2019-03-27 17: 11: 05.738 17082-17082 / com.test.testapp E / TASK: Запущено задание в главном потоке с результатом из Background: значение из фона

Итак, вопрос в том, что думают профессиональные разработчики AndroidТхис решением.Какую проблему я могу получить в случае, если я буду использовать это.И, возможно, есть какая-то причина не использовать это решение.

1 Ответ

1 голос
/ 27 марта 2019

Если вы используете Kotlin, правильный способ сделать это через Coroutines , который позволит вам написать код, такой как:

// Launch a coroutine that by default goes to the main thread
GlobalScope.launch(Dispatchers.Main) {
    // Switch to a background (IO) thread
    val retval = withContext(Dispatchers.IO) {
        Log.e("TASK", "Started background task")
        val retval = "The value from background"
        Thread.sleep(5000)
        Log.e("TASK", "Finished background task with result: " + retval)
        retval
    }
    // Now you're back the main thread
    Log.e("TASK", "Started task in Main thread with result from Background: " + retval)
}

Обратите внимание, что сопрограммы Kotlin работают при структурированном параллелизме , поэтому вам, как правило, следует избегать использования GlobalScope и вместо этого привязать сопрограмму к жизненному циклу Activity / Fragment. Обычно это нужно сделать самостоятельно прямо сейчас.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...