Hàm withTimeout cung cấp cho IllegalStateException: Không có vòng lặp sự kiện. Sử dụng runBlocking {'}} để bắt đầu một. trong ứng dụng khách đa nền tảng của Kotlin


13

Cập nhật: Nó hoạt động nếu lần đầu tiên tôi thực hiện một coroutine mà không có thời gian chờ và sau đó với Timeout. Nhưng nếu tôi thực hiện một coroutine withTimeout trước thì nó sẽ báo lỗi. Async cũng vậy.

Tôi đang tạo một ứng dụng đa nền tảng kotlin demo, nơi tôi đang thực hiện lệnh gọi API với ktor. Tôi muốn có một chức năng hết thời gian cấu hình theo yêu cầu ktor vì vậy tôi đang sử dụng withTimeout ở cấp độ coroutine.

Đây là chức năng gọi của tôi với API mạng.

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
}

Đây là lớp AppDispatcher của tôi cho mô-đun 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()
        }
    }
}

}

vì vậy, chức năng hết thời gian sẽ cho tôi lỗi sau trong ứng dụng khách iOS.

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

Tôi đang sử dụng phiên bản 1.3.2 -igen-mt-1 của kotlin-coroutine -igen. Tôi đã tạo một ứng dụng demo mẫu tại URL sau. https://github.com/dudhatparesh/kotlin-multiplat-pl platform-example


Lỗi chỉ đến trong máy khách iOS? Máy khách Android hoạt động bình thường?
Kushal

Có ứng dụng khách Android đang hoạt động rất tốt
Paresh Dudhat

Đang gặp phải vấn đề tương tự khi cố gắng cập nhật github.com/joreilly/P PeopleInSpace để sử dụng phiên bản mt của coroutines .... 1.3.3-native-mtphiên bản thử được đề cập trong github.com/Kotlin/kotlinx.coroutines/issues/462 . Có vẻ như chúng ta nên sử dụng newSingleThreadContextnhưng điều đó không giải quyết được vì một số lý do.
John O'Reilly

Câu trả lời:


5

Vì vậy, như đã đề cập trong bình luận ở trên, tôi có vấn đề tương tự nhưng hóa ra nó không chọn native-mtphiên bản do phụ thuộc quá độ trong các thư viện khác. Đã thêm sau đây và nó được giải quyết ngay bây giờ.

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

Cũng lưu ý hướng dẫn trong https://github.com/Kotlin/kotlinx.coroutines/blob/native-mt/kotlin-native-shaming.md

Bắt đầu sử dụng điều này trong https://github.com/joreilly/P PeopleInSpace


Chỉ cần thử nó. không làm việc nhận được cùng một lỗi.
Paresh Dudhat

Tôi đã thêm bản sửa lỗi của bạn trên kho lưu trữ tại github.com/dudhatparesh/kotlin-multiplat-pl
platform-example

Nhờ câu trả lời của John, tôi đã có thể gọi hàm dưới đây thành công từ iOS `` `@IternalCoroutinesApi {kprint ("hello \ n") delay (2000) kprint ("world \ n")}}} `` `
Brendan Weinstein

Này John. Cám ơn vì cái này. Bất cứ ý tưởng làm thế nào tôi có thể có được ktor để xây dựng sau đó? Bất cứ cách nào tôi có thể buộc nó sử dụng 1.3.3-native-mt? Tôi nhận đượcCould 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 Cảm ơn một lần nữa. Tôi đã giải quyết nó bằng cách nâng cấp phiên bản lớp của tôi lên 6 như trong ví dụ.
Carson Holzheimer

1

Nếu bạn muốn sử dụng các [withTimeout]chức năng trong coroutines, bạn phải sửa đổi giao diện của mình Dispatcherđể thực hiện Delay. Dưới đây là một ví dụ về cách có thể đạt được điều này:

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

}

Giải pháp này có thể dễ dàng sửa đổi cho nhu cầu của bạn.

Thông tin thêm có thể được tìm thấy trong chủ đề này .


Tôi đã thử giải pháp đó là tốt. Tuy nhiên, đó là lỗi tương tự. tuy nhiên, nếu tôi thực thi bất kỳ coroutine nào không có thời gian chờ trước khi thực hiện coroutine với thời gian chờ thì nó hoạt động tốt.
Paresh Dudhat

@PareshDudhat Hành vi bạn đề cập khá lạ. Có bộ Dispatchers.Unconfinedđiều phối, có cơ chế khá giống với những gì bạn đang mô tả. Bạn có hoàn toàn chắc chắn về cách bạn khởi động coroutine của bạn?
nghệ thuật

Tôi đang khởi chạy nó với launch (Clarkers.main), tôi cũng đã thử khởi chạy nó với công việc disatcher.main + nhưng không có sự giúp đỡ. Tôi đã đưa ra cam kết mới nhất về repo GitHub
Paresh Dudhat

0

Đôi khi ứng dụng ios có yêu cầu không đồng bộ khác với ứng dụng Android. Sử dụng mã này cho vấn đề công văn tạm thời

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

Vui lòng xem diễn đàn về vấn đề này: https://github.com/Kotlin/kotlinx.coroutines/issues/470


Tôi đã thử điều đó nhưng nó không hoạt động tốt.
Paresh Dudhat
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.