简体   繁体   English

Kotlin 协程没有同步运行

[英]Kotlin coroutine does not run synchronously

In all cases that I have been using corrutines, so far, it has been executing its "lines" synchronously, so that I have been able to use the result of a variable in the next line of code.在我一直使用 corrutines 的所有情况下,到目前为止,它一直在同步执行它的“行”,这样我就能够在下一行代码中使用变量的结果。

I have the ImageRepository class that calls the server, gets a list of images, and once obtained, creates a json with the images and related information.我有调用服务器的 ImageRepository class,获取图像列表,一旦获得,就创建一个包含图像和相关信息的 json。

class ImageRepository {

    val API_IMAGES = "https://api.MY_API_IMAGES"

    suspend fun fetch (activity: AppCompatActivity) {

        activity.lifecycleScope.launch() {

            val imagesResponse = withContext(Dispatchers.IO) {
                getRequest(API_IMAGES)
            }

            if (imagesResponse != null) {
                val jsonWithImagesAndInfo = composeJsonWithImagesAndInfo(imagesResponse)

            } else {
                // TODO Warning to user
                Log.e(TAG, "Error: Get request returned no response")
            }

          ...// All the rest of code
        }
    }
}

Well, the suspend function executes correctly synchronously, it first makes the call to the server in the getRequest and, when there is response, then composes the JSON. So far, so good.嗯,suspend function 正确同步执行,它首先在 getRequest 中调用服务器,当有响应时,然后组成 JSON。到目前为止,一切顺利。

And this is the call to the "ImageRepository" suspension function from my main activity:这是我的主要活动对“ImageRepository”暂停 function 的调用:

lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) { neoRepository.fetch(this@MainActivity) }
    Log.i(TAG, "After suspend fun")
}

The problem is that, as soon as it is executed, it calls the suspension function and then displays the log, obviously empty.问题是,一执行就调用暂停function然后显示log,明显是空的。 It doesn't wait for the suspension function to finish and then display the log.它不会等待暂停 function 完成,然后显示日志。

Why?为什么? What am I doing wrong?我究竟做错了什么?

I have tried the different Dispatchers, etc, but without success.我尝试了不同的 Dispatchers 等,但没有成功。

I appreciate any help.我感谢任何帮助。

Thanks and best regards.谢谢并致以最诚挚的问候。

It's because you are launching another coroutine in parallel from inside your suspend function. Instead of launching another coroutine there, call the contents of that launch directly in your suspend function.这是因为您正在从您的暂停 function 中并行启动另一个协程。与其在那里启动另一个协程,不如直接在您的暂停 function 中调用该启动的内容。

A suspend function is just like a regular function, it executes one instruction after another. suspend function 就像普通的 function 一样,一条一条指令执行。 The only difference is that it can be suspended, meaning the runtime environment can decide to halt / suspend execution to do other work and then resume execution later.唯一的区别是它可以暂停,这意味着运行时环境可以决定暂停/暂停执行以执行其他工作,然后稍后恢复执行。

This is true unless you start an asynchronous operation which you should not be doing.这是真的,除非你开始了一个你不应该做的异步操作。 Your fetch operation should look like:您的提取操作应如下所示:

class ImageRepository {

    suspend fun fetch () {
        val imagesResponse = getRequest(API_IMAGES)

        if (imagesResponse != null) {
            val jsonWithImagesAndInfo = composeJsonWithImagesAndInfo(imagesResponse)
        } else {
            // TODO Warning to user
            Log.e(TAG, "Error: Get request returned no response")
        }
        ... // All the rest of code
    }

}

-> just like a regular function. Of course you need to all it from a coroutine: -> 就像常规的 function 一样。当然,您需要从协程中获取所有信息:

lifecycleScope.launch {
    val result = withContext(Dispatchers.IO) { neoRepository.fetch() }
    Log.i(TAG, "After suspend fun")
}

Google recommends to inject the dispatcher into the lower level classes ( https://developer.android.com/kotlin/coroutines/coroutines-best-practices ) so ideally you'd do: Google 建议将调度程序注入较低级别的类 ( https://developer.android.com/kotlin/coroutines/coroutines-best-practices ) 所以理想情况下你会这样做:

val neoRepository = ImageRepository(Dispatchers.IO)

lifecycleScope.launch {
    val result = neoRepository.fetch()
    Log.i(TAG, "After suspend fun")
}

class ImageRepository(private val dispatcher: Dispatcher) {

    suspend fun fetch () = withContext(dispatcher) {
        val imagesResponse = getRequest(API_IMAGES)

        if (imagesResponse != null) {
            val jsonWithImagesAndInfo = composeJsonWithImagesAndInfo(imagesResponse)
        } else {
            // TODO Warning to user
            Log.e(TAG, "Error: Get request returned no response")
        }
        ... // All the rest of code
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM