协程如何等待数据然后继续处理

Coroutines how to wait for the data and then continue process

我正在学习使用 kotlin 的协程,但我有一个问题,即进程如何等到进程 1 完成,然后继续处理 2,从我下面的示例中,我有对象网络,它使用 getNews 访问 API 服务器(已经运行好了,获取数据) 我使用异步 - 等待从 refreshNews 调用这个 getNews,目的是等待数据然后继续 运行,但是 "The program Not Wait",它只是 运行 进程 2 然后进程 1 完成,所以我无法在刷新新闻

中捕获来自 API 的数据
// process 1 - calling api this running well can get the data see process 2

object Network {
    var status : NewsApiStatus =  NewsApiStatus.LOADING

    private var viewModelJob = Job()
    private val coroutineScope = CoroutineScope(viewModelJob + Dispatchers.Main)

    fun getNews(filter: String, page: Int =1) : newsData? {
        var allNews : newsData? = null
        coroutineScope.launch {
            RetrofitClient.instance.getAllNews(filter, page).enqueue(object: Callback<newsData>{
                override fun onFailure(call: Call<newsData>, t: Throwable) {
                    status = NewsApiStatus.ERROR
                }

                override fun onResponse(
                    call: Call<newsData>,
                    response: Response<newsData>
                ) {
                    status = NewsApiStatus.DONE
                    var listResult = response.body()
                    if (listResult != null) {
                        if (listResult.data.isNotEmpty())  {
                            allNews = listResult
                            Timber.tag(TAG).i( "process 1 total allNews = ${allNews!!.data.size}")
                        }
                    }
                }
            })
        }
        return(allNews)
    }
}

// process 2 - calling process 1 with runBlocking

fun refreshNews() = runBlocking{
    val newsData = async {
        Network.getNews("")
    }
    Timber.tag(TAG).i("proses 2 ${newsData.await()?.data?.size}")
    // here I want newsData to wait until it has data
}

// this main program that call process 2

class NewsListViewModel(application: Application) : AndroidViewModel(application) {
    init {
        refreshNews()
    }
}

launch return 是对已启动作业的引用。您可以使用它来等待作业完成,方法是调用 join():

val job = GlobalScope.launch { // launch a new coroutine and keep a reference to its Job
    // ...
}
runBlocking {
    job.join() // wait until child coroutine completes
}

目前,您的 getNews() 启动协程并立即 returns。 allNews 此时尚未初始化。

您需要在 getNews() 中调用 job.join()(会导致阻塞),或者在 getNews() 和 return 中使用异步,如果您想保留其结果它是异步的(您需要采用与您的 http 客户端不同的结果,因为您将无法初始化在外部声明的变量)。

值得阅读官方协程文档: