withTimeout işlevi IllegalStateException değerini verir: Olay döngüsü yoktur. Birini başlatmak için runBlocking {…} kullanın. Kotlin Multiplatform iOS istemcisinde


13

Güncelleme: İlk önce zaman aşımı olmadan bir coroutine çalıştırırsam ve ardından Timeout ile çalışır. Ama önceTimeout ile birlikte bir program çalıştırırsam bana bir hata verir. Async için de aynı şey geçerli.

Ktor ile bir API çağrısı yürüttüğüm bir demo kotlin çoklu platform uygulaması oluşturuyorum. Ben coroutine düzeyinde withTimeout ile kullanıyorum bu yüzden ktor istek üzerine yapılandırılabilir bir zaman aşımı işlevi olmasını istiyorum.

İşte ağ API ile benim işlev çağrısı.

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
}

İşte iOSMain modülü için AppDispatcher sınıfım.

@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()
        }
    }
}

}

böylece zaman aşımına sahip işlev iOS istemcisinde bana aşağıdaki hatayı veriyor.

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

Kotlin-coroutine-native'in 1.3.2-yerli-mt-1 versiyonunu kullanıyorum. Aşağıdaki URL'de örnek bir demo uygulaması oluşturdum. https://github.com/dudhatparesh/kotlin-multiplat-platform-example


Hata yalnızca iOS istemcisinde mi geliyor? Android istemcisi düzgün çalışıyor mu?
Kushal

Evet Android istemcisi gayet iyi çalışıyor
Paresh Dudhat

Güncelleştirmeye çalışırken benzer konuya çalışan muyum github.com/joreilly/PeopleInSpace değiş tokuş eden kavramlar yerli mt sürümünü kullanmaya çalışıyor .... 1.3.3-native-mtbelirtilen versiyonunu github.com/Kotlin/kotlinx.coroutines/issues/462 . Kullanmalıyız gibi görünüyor, newSingleThreadContextancak bu herhangi bir nedenle çözülmüyor.
John O'Reilly

Yanıtlar:


5

Yani, yukarıdaki yorumda belirtildiği gibi benzer bir sorunum vardı, ancak native-mtdiğer kütüphanelerdeki geçişli bağımlılıklar nedeniyle sürümü almadım. Aşağıdaki eklendi ve şimdi çözülüyor.

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

Ayrıca https://github.com/Kotlin/kotlinx.coroutines/blob/native-mt/kotlin-native-sharing.md adresindeki rehbere de dikkat edin.

Bunu https://github.com/joreilly/PeopleInSpace adresinden kullanmaya başlama


Sadece denedim. aynı hatayı almak işe yaramadı.
Paresh Dudhat


John'un cevabı sayesinde aşağıdaki işlevi iOS'tan başarılı bir şekilde arayabildim `` @InternalCoroutinesApi fun backgroundTest () {val job = GlobalScope.launch {kprint ("ana iplikteyiz \ n") ileContext (Dispatchers.Default) {kprint ("merhaba \ n") gecikme (2000) kprint ("dünya \ n")}}}} ``
Brendan Weinstein

Selam John. Bunun için teşekkürler. O zaman ktor'u nasıl inşa edebileceğime dair bir fikrin var mı? Herhangi bir şekilde kullanmaya zorlayabilir miyim 1.3.3-native-mt? AnladımCould 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
Carson Holzheimer

1
@ JohnO'Reilly Tekrar teşekkürler. Gradle versiyonumu örnekte olduğu gibi 6'ya yükselterek çözdüm.
Carson Holzheimer

1

[withTimeout]Coroutines işlevlerini kullanmak istiyorsanız, arabirim Dispatcheruygulamak için değiştirmek gerekir Delay. İşte bunun nasıl başarılabileceğine dair bir örnek:

@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
    }

}

Bu çözüm ihtiyaçlarınıza göre kolayca değiştirilebilir.

Daha fazla bilgi bulunabilir Bu konuya .


Bu çözümü de denedim. yine de aynı hatayı veriyor. ancak, zaman aşımı ile birlikte çalışma yürütmeden önce zaman aşımı olmayan herhangi bir ortak program yürütürsem iyi çalışır.
Paresh Dudhat

@PareshDudhat Bahsettiğiniz davranış oldukça garip. Dispatchers.UnconfinedAçıkladığınız şeye oldukça benzer bir mekanizmaya sahip olan dağıtıcı vardır . Ortak programınızı başlatma şeklinizden tam olarak emin misiniz?
sanat

Ben lansmanı (dispatchers.main) ile başlatıyorum, ben de dispatcher.main + iş ile başlatmayı denedim ama yardım yok. GitHub
repo'daki

0

Bazen ios uygulaması bir android uygulaması ile farklı bir zaman uyumsuzluk gereksinimi vardır. Geçici gönderim sorunu için bu kodu kullanın

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

Lütfen bu sorunla ilgili foruma bakın: https://github.com/Kotlin/kotlinx.coroutines/issues/470


Bunu denedim ama işe yaramıyor.
Paresh Dudhat
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.