withTimeout函数给出IllegalStateException:不存在事件循环。使用runBlocking{…}启动一个。在Kotlin多平台iOS客户端中
更新: 如果我先在没有超时的情况下执行一个协同程序,然后在没有超时的情况下执行,那么它就会工作。但是如果我先执行一个带有超时的协同程序,那么它会给我一个错误。异步也是如此 我正在创建一个演示kotlin多平台应用程序,其中我正在使用ktor执行一个API调用。 我想在ktor请求上有一个可配置的超时函数,所以我在协同程序级别使用withTimeout 这是我使用网络API进行的函数调用withTimeout函数给出IllegalStateException:不存在事件循环。使用runBlocking{…}启动一个。在Kotlin多平台iOS客户端中,ios,kotlin,kotlin-coroutines,ktor,kotlin-native,Ios,Kotlin,Kotlin Coroutines,Ktor,Kotlin Native,更新: 如果我先在没有超时的情况下执行一个协同程序,然后在没有超时的情况下执行,那么它就会工作。但是如果我先执行一个带有超时的协同程序,那么它会给我一个错误。异步也是如此 我正在创建一个演示kotlin多平台应用程序,其中我正在使用ktor执行一个API调用。 我想在ktor请求上有一个可配置的超时函数,所以我在协同程序级别使用withTimeout 这是我使用网络API进行的函数调用 suspend fun <T> onNetworkWithTimeOut( url: St
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
}
}
因此,带有超时的函数在iOS客户端中给了我以下错误
kotlin.IllegalStateException: There is no event loop. Use runBlocking { ... } to start one.
我正在使用1.3.2-native-mt-1版本的kotlin协同程序native。
我已经在下面的URL创建了一个示例演示应用程序。
因此,正如上面的评论中提到的,我也有类似的问题,但由于其他库中的可传递依赖关系,它没有选择
本机mt
版本。添加了以下内容,现在正在解决
implementation('org.jetbrains.kotlinx:kotlinx-coroutines-core-native')
{
version {
strictly '1.3.3-native-mt'
}
}
另请注意中的指导
有时ios应用程序对android应用程序有不同的异步要求。 使用此代码解决临时调度问题
object MainLoopDispatcher: CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
NSRunLoop.mainRunLoop().performBlock {
block.run()
}
}
}
请参阅论坛了解此问题:如果您想在协同程序中使用
[withTimeout]
函数,您必须修改调度程序来实现接口。以下是如何实现这一目标的示例:
@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
}
}
错误只出现在iOS客户端?安卓客户端工作正常?是的,安卓客户端工作正常。在尝试更新以使用coroutines的本机mt版本时,我遇到了类似问题……正在尝试中提到的1.3.3-native-mt
版本。似乎我们应该使用newSingleThreadContext
,但由于某些原因,这并不能解决问题。只是尝试了一下。没有得到相同的错误。由于John的回答,我已经在存储库中添加了您的修复程序。我能够从iOS```@InternalCoroutinesApi fun backgroundTest(){val job=GlobalScope.launch{kprint(“我们在主线程上”)和context(Dispatchers.Default){kprint(“hello\n”)delay(2000)kprint(“world\n”)}}}``嘿,约翰。谢谢你。你知道我怎样才能让ktor建造吗?我是否可以强制它使用1.3.3-native-mt
?我得到无法解析org.jetbrains.kotlinx:kotlinx coroutines核心本机:1.3.3。需要:项目:共享>io.ktor:ktor客户端ios:1.3.0>io.ktor:ktor-client-ios-IOS64:1.3.0
@JohnO'Reilly再次感谢。我通过将gradle版本升级到6解决了这个问题,就像您在示例中所做的那样。我也尝试了这个解决方案。尽管如此,它还是给出了同样的错误。然而,如果我在执行带有超时的协同程序之前执行任何没有超时的协同程序,它就可以正常工作。@PareshDudhat您提到的行为相当奇怪。还有dispatcher,它与您描述的内容非常相似。您完全确定启动协同程序的方式吗?我使用launch(dispatchers.main)启动它,我也尝试过使用dispatcher.main+job启动它,但没有任何帮助。我在GitHub上推送了最新的提交,我只想在一个挂起函数中调用delay,这个解决方案工作得很好!谢谢@art
@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
}
}
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9-native-mt") {
version {
strictly('1.3.9-native-mt')
}
}