Функція withTimeout дає IllegalStateException: Немає циклу подій. Використовуйте runBlocking {…}, щоб почати його. у клієнті iOS клієнта Multiplatform iOS


13

Оновлення: працює, якщо спершу виконати супровід без таймауту, а потім - зTimeout. Але якщо я спочатку виконую програму зTimeout, то це дає мені помилку. те саме стосується і Async.

Я створюю багатоплатформенний додаток kotlin, де я виконую виклик API з ktor. Я хочу мати налаштовану функцію тайм-ауту на запит ktor, тому я використовую withTimeout на рівні програми.

Ось мій виклик функції з мережевим API.

suspend fun <T> onNetworkWithTimeOut(
    url: String,
    timeoutInMillis: Long,
    block: suspend CoroutineScope.() -> Any): T {
    return withTimeout(timeoutInMillis) {
        withContext(dispatchers.io, block)
    } as T
}

suspend fun <T> onNetworkWithoutTimeOut(url: String, block: suspend CoroutineScope.() -> Any): T {
    return withContext(dispatchers.io, block) as T
}

Ось мій клас AppDispatcher для модуля iOSMain.

@InternalCoroutinesApi
actual class AppDispatchersImpl : AppDispatchers {
@SharedImmutable
override val main: CoroutineDispatcher =
    NsQueueDispatcher(dispatch_get_main_queue())

@SharedImmutable
override val io: CoroutineDispatcher =
    NsQueueDispatcher(dispatch_get_main_queue())

internal class NsQueueDispatcher(
    @SharedImmutable private val dispatchQueue: dispatch_queue_t
) : CoroutineDispatcher() {
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        NSRunLoop.mainRunLoop().performBlock {
            block.run()
        }
    }
}

}

тому функція з таймаутом дає мені таку помилку в iOS-клієнті.

kotlin.IllegalStateException: There is no event loop. Use runBlocking { ... } to start one.

Я використовую 1.3.2-native-mt-1 версію kotlin-coroutine-native. Я створив зразок демонстраційної програми за наступною URL-адресою. https://github.com/dudhatparesh/kotlin-multiplat-platform-example


Помилка надходить лише у клієнт iOS? Android-клієнт працює належним чином?
Kushal

Так, клієнт Android працює прекрасно
Paresh Dudhat

Зустрічаюсь з подібною проблемою при спробі оновити github.com/joreilly/PeopleInSpace для використання рідної версії mt підпрограм .... випробувальна 1.3.3-native-mtверсія, зазначена в github.com/Kotlin/kotlinx.coroutines/isissue/462 . Здається, ми повинні використовувати, newSingleThreadContextале це не вирішує з якихось причин.
Джон О'Рейлі

Відповіді:


5

Отже, як згадувалося в коментарі вище, у мене був подібний випуск, але виявилося, що він не підбирав native-mtверсію через транзитивні залежності в інших бібліотеках. Додано наступне, і це вирішується зараз.

        implementation('org.jetbrains.kotlinx:kotlinx-coroutines-core-native') 
        {
            version {
                strictly '1.3.3-native-mt'
            }
        }

Також зверніть увагу на вказівки https://github.com/Kotlin/kotlinx.coroutines/blob/native-mt/kotlin-native-sharing.md

Починаючи використовувати це в https://github.com/joreilly/PeopleInSpace


Просто спробував це. не вдалося отримати ту ж помилку.
Paresh Dudhat

Я додав ваше виправлення до сховища на сайті github.com/dudhatparesh/kotlin-multiplat-platform-example
Paresh Dudhat

Завдяки відповіді Джона мені вдалося зателефонувати нижче на функцію з iOS `` `@InternalCoroutinesApi fun backgroundTest () {val job = GlobalScope.launch {kprint (" ми в основному потоці \ n ") зContext (Dispatchers.Default) {kprint ("привіт \ n") затримка (2000) kprint ("світ \ n")}}}} ``
Брендан Вайнштейн

Гей, Джон. Дякую за це Будь-яка ідея, як я можу змусити ktor будувати тоді? Якимось чином я можу змусити це використовувати 1.3.3-native-mt? Я отримуюCould not resolve org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.3.3. Required by: project :shared > io.ktor:ktor-client-ios:1.3.0 > io.ktor:ktor-client-ios-iosx64:1.3.0
Карсон Хольцгеймер,

1
@ JohnO'Reilly Ще раз дякую. Я вирішив це, оновивши мою версію gradle до 6, як у вас у прикладі.
Карсон Хольцгеймер

1

Якщо ви хочете використовувати [withTimeout]функції в підпрограмах, вам слід змінити інтерфейс Dispatcherдля реалізації Delay. Ось приклад того, як цього можна досягти:

@UseExperimental(InternalCoroutinesApi::class)
class UI : CoroutineDispatcher(), Delay {

    override fun dispatch(context: CoroutineContext, block: Runnable) {
        dispatch_async(dispatch_get_main_queue()) {
            try {
                block.run()
            } catch (err: Throwable) {
                throw err
            }
        }
    }

    @InternalCoroutinesApi
    override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeMillis * 1_000_000), dispatch_get_main_queue()) {
            try {
                with(continuation) {
                    resumeUndispatched(Unit)
                }
            } catch (err: Throwable) {
                throw err
            }
        }
    }

    @InternalCoroutinesApi
    override fun invokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle {
        val handle = object : DisposableHandle {
             var disposed = false
                private set

            override fun dispose() {
                disposed = true
            }
        }
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeMillis * 1_000_000), dispatch_get_main_queue()) {
            try {
                if (!handle.disposed) {
                    block.run()
                }
            } catch (err: Throwable) {
                throw err
            }
        }

        return handle
    }

}

Це рішення можна легко модифікувати для ваших потреб.

Більше інформації можна знайти в цій темі .


Я також спробував це рішення. все-таки, це дає ту саму помилку. однак, якщо я виконую будь-яку програму, яка не має часу очікування перед виконанням програми з таймаутом, вона працює чудово.
Paresh Dudhat

@PareshDudhat Поведінка, яку ви згадали, досить дивна. Є Dispatchers.Unconfinedдиспетчер, у якого механізм досить схожий на те, що ви описуєте. Ви повністю впевнені у способі запуску програми?
мистецтво

Я запускаю його із запуском (depeche.main), я також спробував запустити його за допомогою dischercher.main + робота, але ніякої допомоги. Я підштовхнув останню
Paresh Dudhat

0

Іноді програма ios має іншу вимогу асинхронізації з додатком для Android. Використовуйте цей код для тимчасової проблеми з відправленням

object MainLoopDispatcher: CoroutineDispatcher() {
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        NSRunLoop.mainRunLoop().performBlock {
            block.run()
        }
    }
}

Будь ласка, перегляньте форум для цього питання: https://github.com/Kotlin/kotlinx.coroutines/isissue/470


Я спробував це, але це також не працює.
Paresh Dudhat
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.