Mise à jour: Cela fonctionne si j'exécute d'abord une coroutine sans timeout puis avec Timeout. Mais si j'exécute d'abord une coroutine avec Timeout, cela me donne une erreur. il en va de même pour Async.
Je crée une application multiplateforme de démonstration kotlin où j'exécute un appel d'API avec ktor. Je veux avoir une fonction de temporisation configurable sur demande ktor, donc j'utilise withTimeout au niveau coroutine.
Voici mon appel de fonction avec l'API réseau.
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
}
Voici ma classe AppDispatcher pour le module 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()
}
}
}
}
donc la fonction avec le timeout me donne l'erreur suivante dans le client iOS.
kotlin.IllegalStateException: There is no event loop. Use runBlocking { ... } to start one.
J'utilise la version 1.3.2-native-mt-1 de la kotlin-coroutine-native. J'ai créé un exemple d'application de démonstration à l'URL suivante. https://github.com/dudhatparesh/kotlin-multiplat-platform-example
Si vous souhaitez utiliser [withTimeout]
fonctions dans les coroutines vous devez modifier votre Dispatcher
pour implémenter l'interface Delay
. Voici un exemple de la façon dont cela peut être réalisé:
@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
}
}
Cette solution peut être facilement modifiée selon vos besoins.
Plus d'informations peuvent être trouvées dans ce fil .
Parfois, l'application ios a une exigence asynchrone différente avec une application Android. Utilisez ce code pour un problème de répartition temporaire
object MainLoopDispatcher: CoroutineDispatcher() {
override fun dispatch(context: CoroutineContext, block: Runnable) {
NSRunLoop.mainRunLoop().performBlock {
block.run()
}
}
}
Veuillez consulter le forum pour ce problème: https://github.com/Kotlin/kotlinx.coroutines/issues/47