问题描述
对于Kotlin协程这件事我还很陌生,我对工作计划有一个问题。在下面的这段代码中,首先我从片段中的用户缓存中获取主题名称。(topicslist) 然后,我需要一一从API中获取这些主题。我想做的是遍历Topicslist,为每个主题发出一个请求,并在所有请求完成时获得所有响应一次。为了实现这一点,在getEverything()方法(触发请求)中,我每次都将响应添加到arraylist中。(responseList) 在for循环中,我启动了所有请求。作业完成后,将调用job.invokeOnCompletion {},并将liveData设置为responseList。但是,这种方法不起作用。问题是,我在设置responseList之前正在更新liveData。我不知道怎么可能。有人可以帮我吗?
val topicslist = dataMap["topics"] // GOT THE TOPICS
topicslist?.let {
var job: Job
Coroutinescope(dispatchers.Main).launch {
job = launch {
for (topic in topicslist) {
mviewmodel.getEverything(topic,API_KEY)
}
}
job.join()
job.invokeOnCompletion {
mviewmodel.updateLiveData()
}
}
} ?: throw Exception("NULL")
viewmodel中的getEverything()方法:
suspend fun getEverything(topic: String,apiKey: String) {
viewmodelScope.launch {
_isLoading.value = true
withContext(dispatchers.IO) {
val response = api.getEverything(topic,apiKey)
withContext(dispatchers.Main) {
if (response.isSuccessful) {
if (response.body() != null) {
responseList.add(response.body()!!)
println("Response is successful: ${response.body()!!}")
_isLoading.value = false
_isError.value = false
}
}
else {
Log.d(TAG,"getEverything: ${response.errorBody()}")
_isError.value = true
_isLoading.value = false
}
}
}
}
}
然后,updateLiveData方法:
fun updateLiveData() {
_newsResponseList.value = responseList
println("response list : ${responseList.size}")
responseList.clear()
}
这是它在日志中的样子:Logs
为无法打开图像的用户记录日志:
I/System.out: response list : 0
I/System.out: Response is successful: NewsResponse(articleList=[Article(source=Source(id=wired,...
I/System.out: Response is successful: NewsResponse(articleList=[Article(source=Source(id=techcrunch,...
I/System.out: Response is successful: NewsResponse(articleList=[Article(source=Source(id=wired,...
I/System.out: Response is successful: NewsResponse(articleList=[Article(source=Source(id=the-verge,...
Btw数据被正确无误地获取。我对此没有问题。
解决方法
问题是getEverything
使用launch
创建后台作业,然后在知道作业完成之前返回。
要解决此问题,请让getEverything
直接返回数据:
suspend fun getEverything(topic: String,apiKey: String): Response? {
_isLoading.value = true
val response = withContext(Dispatchers.IO) {
api.getEverything(topic,apiKey)
}
_isLoading.value = false
return response.takeIf { it.isSuccessful }?.body()?.let { body ->
println("Response is successful: $body")
}.also {
_isError.value = it == null
}
}
在片段中,请求结果并分配它们:
lifecycleScope.launch {
_responseList.value = topicsList.mapNotNull { topic ->
model.getResponse(topic,apiKey)
}
}