#kotlin #asynchronous #kotlin-coroutines #suspend
#kotlin #асинхронный #kotlin-сопрограммы #приостановить
Вопрос:
Я вызываю Api из функции приостановки, и после ее успешного выполнения мне нужно вызвать другой Api (который также находится в другой функции приостановки).
suspend fun updateSubscription(body: Map<String, Any>): NetworkResponse<SubscriptionUpdateResponse> =
withContext(Dispatchers.IO) {
val response = networkManager.execute(
networkManager.updateSubscriptionApi(body)
)
val data = response.body()
if (response.isSuccessful) {
fetchSubscriptions() // suspend function which call another api, should run without blocking
}
return@withContext parseNetworkResponse(response, data)
}
Я хочу вызвать updateSubscriptionApi
и после его успешного выполнения вызвать fetchSubscription
без блокировки и вернуть updateSubscription
результат.
На данный момент fetchSubscription
также блокируется updateSubscription
. Я пытался вызвать updateSubscription
такой async
блок, но безуспешно.
async{ updateSubscription() }
Как я могу вызвать fetchSubscriptions()
без блокировки updateSubscription
.
Ответ №1:
К сожалению, ваше требование, чтобы функция одновременно приостанавливала и запускала параллельную работу, которая все еще активна при возврате функции, считается антишаблоном в Kotlin и имеет некоторые трудности в его достижении.
Но сначала простые вещи:
- Вы уверены, что вам нужен
IO
диспетчер? Вы сказали, что сетевой вызов приостанавливается, что означает неблокирующий и не требует выделенного диспетчера ввода-вывода. - Если вам это нужно (на самом деле это блокирующий вызов), не включайте в него весь код, а только этот вызов.
Теперь самое сложное. Чтобы иметь возможность запускать сопрограмму, важно учитывать, в какой области вы ее запускаете. Kotlin настоятельно рекомендует использовать структурированный параллелизм, что означает запуск всего в четко определенной области действия вашего элемента пользовательского интерфейса (activity и т. Д.). В вашем случае вы должны явно передать область видимости в качестве параметра функции. Обычно вы объявляете ее как расширение on CoroutineScope
, но это не работает для приостановки функций из-за коллизии имен on coroutineContext
, которая является как глобальной val
, так и свойством CoroutineScope
. Это означает, что ваш код может выглядеть следующим образом:
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
suspend fun updateSubscription(
scope: CoroutineScope,
body: Map<String, Any>
): NetworkResponse<SubscriptionUpdateResponse> {
val response = withContext(Dispatchers.IO) { // only if you need it!
networkManager.execute(networkManager.updateSubscriptionApi(body))
}
if (response.isSuccessful) {
scope.launch { fetchSubscriptions() }
}
return parseNetworkResponse(response, response.body())
}
Комментарии:
1. Да, мне нужен
IO
диспетчер, потому что мой вызов блокировался. Я попробовал ваше решение, и оно работает для меня. Спасибо