更新: 如果我先执行没有超时的协程,然后再执行超时,则它会起作用。但是,如果我先用timeout执行协程,则会给我一个错误。异步也是如此。
我正在创建一个演示kotlin跨平台应用程序,并在其中使用ktor执行API调用。 我想对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
}
这是我的iOSMain模块的AppDispatcher类。
@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.
我正在使用kotlin-coroutine-native的1.3.2-native-mt-1版本。 我已经在以下URL创建了一个示例演示应用程序。 https://github.com/dudhatparesh/kotlin-multiplat-platform-example
答案 0 :(得分:2)
因此,如上所述,我遇到了类似的问题,但事实证明,由于其他库中的传递性依赖关系,它没有采用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中的指南
中使用它答案 1 :(得分:1)
有时ios应用程序与android应用程序具有不同的异步要求。 使用此代码解决临时调度问题
object MainLoopDispatcher: CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
NSRunLoop.mainRunLoop().performBlock {
block.run()
}
}
}
请访问此问题的论坛:https://github.com/Kotlin/kotlinx.coroutines/issues/470
答案 2 :(得分: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
}
}
可以轻松修改此解决方案以满足您的需求。
更多信息可以在this thread中找到。