协程如何等待数据然后继续处理
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 客户端不同的结果,因为您将无法初始化在外部声明的变量)。
值得阅读官方协程文档:
我正在学习使用 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 客户端不同的结果,因为您将无法初始化在外部声明的变量)。
值得阅读官方协程文档: