Coroutine - отказ от использования функции приостановки
Я новичок в KMM и сопрограммах. Есть ли способ дождаться ответа от асинхронной функции, не заставляя зависимую функцию также приостанавливаться?
Пример кода
// In HttpClient.kt in commonMain
class MyHttpClient {
val client = HttpClient()
suspend fun get(url: String): String {
client.get<String>(url)
}
}
// In Another class in commonMain
class Foo {
private val httpClient = MyHttpClient()
fun performAction() { <--- #1
val data = httpClient.get("server url")
// So stuff with that data after its retrieve from server.
}
}
// In iOS swift code
struct Example: View {
var body: some View {
Button {
foo.performAction() <--- #2
} label: {
Text("Click Me")
}
}
}
если я делаю № 1, то функция приостановки № 2 требует ненужного обратного вызова. пример
// In iOS swift code
struct Example: View {
var body: some View {
Button {
foo.performAction(completionHandler: handler)
} label: {
Text("Click Me")
}
}
private func handler(response: KotlinUnit?, error: Error?) {
// DO NOTHING
}
}
Также мой модульный тест не работает, потому что вы не можете сделать тестовые функции приостановки и
runBlocking
нет общего
2 ответа
Вам нужно указать сопрограмму, на которой должен запускаться ваш метод.
fun performAction() { <--- #1
CoroutineScope(Dispatchers.Default).launch {
val data = httpClient.get("server url")
// So stuff with that data after its retrieve from server.
MainScope().launch {
// if you need to update UI from the main thread, call it here
}
}
}
Вам не нужно добавлять этот обратный вызов завершения. Все, что вам нужно сделать, это запустить сопрограмму из обработчика кликов, например:
Button {
viewScope.launch {
foo.performAction()
// add GUI code here that runs when action is done
}
} label: {
Text("Click Me")
}
Если у вас в настоящее время не определена область сопрограммы, вы должны добавить ее примерно так:
struct Example: View {
private val viewScope = CoroutineScope(Dispatchers.Main)
// adapt this to the actual way you get the "view closed" event
fun onClose() {
viewScope.cancel()
}
...
}
Это заставляет вашу сопрограмму работать в потоке графического интерфейса. Поскольку вы используете приостанавливаемый ввод-вывод (что подтверждается вашим
suspend fun get(url: String): String
), нет необходимости использовать какой-либо другой поток.