Чтобы ответить на ваш ближайший вопрос, вы должны просто запустить сопрограмму в правильном контексте:
val call = ApiClient.getInterface().getRoute(request.getURL())
GlobalScope.launch(Dispatchers.Main) {
try {
success?.invoke(call.await())
} catch (t: Throwable) {
fail?.invoke(t)
}
}
Однако это будет лишь верхушка айсберга, потому что ваш подход - неправильный способ использования сопрограмм. Их ключевое преимущество - избегать обратных вызовов, но вы их снова вводите. Вы также нарушаете структурированный параллелизм передовой опыт, используя GlobalScope
, который не предназначен для производственного использования.
Очевидно, у вас уже есть асинхронный API, который дает вам Deferred<RoutesResponse>
, который вы можете await
включить. Способ его использования заключается в следующем:
scope.launch {
val resp = ApiClient.getInterface().getRoute(request.getURL()).await()
updateGui(resp)
}
Вы можете быть огорчены тем фактом, что я предлагаю иметь блок launch
в каждом обратном вызове графического интерфейса пользователя, где вы должны выполнить приостанавливаемый код, но на самом деле это рекомендуемый способ использования этой функции. Он строго параллелен написанию Thread { ... my code ... }.start()
, потому что содержимое вашего launch
блока будет одновременно выполняться с кодом за его пределами.
Приведенный выше синтаксис предполагает, что у вас есть готовая переменная scope
, которая реализует CoroutineScope
. Например, это может быть ваш Activity
:
class MyActivity : AppCompatActivity(), CoroutineScope {
lateinit var masterJob: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + masterJob
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
masterJob = Job()
}
override fun onDestroy() {
super.onDestroy()
masterJob.cancel()
}
}
Обратите внимание, как coroutineContext
устанавливает диспетчер сопрограмм по умолчанию на Dispatchers.Main
. Это позволяет использовать простой синтаксис launch { ... }
.