我对Kotlin-coroutine很陌生,并且在工作计划方面遇到问题。在下面的这段代码中,首先我从片段中的用户缓存中获取主题名称。(topicsList)
然后,我需要一一从API中获取这些主题。我想做的是遍历TopicsList,为每个主题发出一个请求,并在所有请求完成时获得所有响应一次。为了实现这一点,在getEverything()方法(触发请求)中,我每次都将响应添加到arraylist中。(responseList)
在for循环中,我触发了所有请求。作业完成后,将调用job.invokeOnCompletion {},并将liveData设置为responseList。但是,这种方法不起作用。问题是,我在设置responseList之前正在更新liveData。我不知道怎么可能。有人可以帮我吗?
这是myFragment中的CoroutineScope:

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, ...
顺便提一下数据,没有错误及其正确。我对此没有问题。

最佳答案

问题是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)
    }
}

10-07 14:56