3

我正在为 Android 和 iOS 制作一个 Kotlin 多平台项目。我的目标是在公共模块中进行网络和 JSON 序列化,并在目标平台中使用该数据。

但我有一个问题:它阻止了 iOS 应用程序上的 UI。下载很好,因为它是通过网络库完成的,但是当 JSON 足够大并且序列化需要一些时间时,它会冻结 UI,直到序列化完成。

这是我的步骤:

常见的

使用 ktor 库的请求方法:

class NetworkProvider {
    private val client = HttpClient()
    suspend fun request(urlString: String): String {
        return client.request<String>(urlString)
    }
}

带有 JSON 序列化的请求方法:

suspend fun request(): CustomObject {
    val json = networkProvider.request("API endpoint")
    val object = Json.nonstrict.parse(CustomObject().serializer(), json)
    return object
}

执行请求:

class Downloader {
    var listener: DownloadListener? = null
    fun download() {
        CustomCoroutineScope().launch {
            val object = request()
            listener?.onCompleted(object)
        }
    }
}

调度程序和协程范围:

class UIDispatcher : CoroutineDispatcher() {
    override fun dispatch(context: CoroutineContext, block: Runnable) {
        dispatch_async(dispatch_get_main_queue()) {
            block.run()
        }
    }
}

internal class CustomCoroutineScope : CoroutineScope {
    private val dispatcher = UIDispatcher()
    private val job = Job()
    override val coroutineContext: CoroutineContext
        get() = dispatcher + job
}

iOS

实现DownloadListener方法:

func onCompleted(object: CustomObject) {
    // Update the UI
 }

并调用请求

downloader.download()

我假设它应该在主线程中异步执行而不会阻塞 UI。

我究竟做错了什么?我在调用协程时尝试使用withContext,但没有帮助。

有没有什么办法可以在公共模块中做繁重的任务而不阻塞特定平台的UI?

4

2 回答 2

3

一旦您的网络调用完成,您的 Json 解析将在主线程上结束。这将阻塞主线程上的所有其他东西,包括 ui。您需要将 Json 解析发送到后台线程。下面是一些使用 kotlin 多平台的并发示例

https://github.com/touchlab/DroidconKotlin/blob/master/sessionize/lib/src/commonMain/kotlin/co/touchlab/sessionize/platform/Functions.kt

于 2019-04-06T14:47:40.323 回答
3

JSON 解析是一项繁重的任务,需要在后台线程上完成。不要在主队列上异步调度,而是在全局队列上异步调度。

于 2019-04-06T19:15:23.453 回答