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

wid*_*ayd 9 coroutine kotlin kotlin-coroutines

我正在用 kotlin 学习协程,我有一个问题,进程如何等待进程 1 完成,然后继续处理 2,从下面的示例中,我有一个使用 getNews 访问 API 服务器的对象网络(它运行良好并获取数据)我使用异步等待从refreshNews调用这个getNews,其目的是等待数据然后继续运行,但是“程序不等待”,它只是运行进程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()
    }
}
Run Code Online (Sandbox Code Playgroud)

Jak*_*las 9

launch返回对已启动作业的引用。您可以通过调用它来等待作业完成join()

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

目前,您getNews()启动了一个协程并立即返回。 allNews此时尚未初始化。

您需要job.join()在内部调用getNews()(会使其阻塞),或者getNews()如果您想保持异步,则在内部使用 async 并返回其结果(您需要以与 http 客户端不同的方式获取结果,因为您将无法初始化外部声明的变量)。

值得阅读官方协程文档: