【发布时间】:2020-10-15 21:08:37
【问题描述】:
我在我的代码中使用嵌套的协程块。当我尝试将延迟类型的结果传递给变量时,我得到了一个空值。因此,它会导致转换问题,即 kotlin.TypeCastException: null cannot be cast to non-null type kotlin.collections.ArrayList in getNearbyHealthInstitutions() 方法的返回行。我相信,我在某个时候做了正确的实现,但是我缺少什么来从 Deferred 的结果中获取空值?有趣的是,当我调试它时,它确实返回了预期值。我认为这应该是并发问题,或者我不知道为什么它首先在调试模式下工作。有什么想法吗?
// Invocation point where resides in a callback
GlobalScope.launch(Dispatchers.Main) {
nearbyHealthInstitutionSites.value = getNearbyHealthInstitutions()
}
private suspend fun getNearbyHealthInstitutions(radius: Meter = DEFAULT_KM_RADIUS) : ArrayList<Hospital> {
return CoroutineScope(Dispatchers.IO).async {
val list = getHealthInstitutions()
val filteredList = list?.filter { it.city == state?.toUpperCase() } as MutableList<Hospital>
Log.i(MTAG, "nearby list is $filteredList")
Log.i(MTAG, "nearby list's size is ${filteredList.size}")
var deferred: Deferred<MutableList<Hospital>>? = null
addAllNearbyLocations(onEnd = { nearbyHealthInstitutions ->
deferred = async {
findNearbyOfficialHealthInstitutions(
officialHealthInstitutionList = filteredList as ArrayList<Hospital>,
nearbyHealthInstitutions = nearbyHealthInstitutions
)
}
})
val result = deferred?.await()
return@async result as ArrayList<Hospital>
}.await()
}
private suspend fun findNearbyOfficialHealthInstitutions(officialHealthInstitutionList: ArrayList<Hospital>, nearbyHealthInstitutions: MutableList<Hospital>): MutableList<Hospital> {
return GlobalScope.async(Dispatchers.Default) {
val result = mutableListOf<Hospital>()
officialHealthInstitutionList.forEach {
nearbyHealthInstitutions.forEach { hospital ->
StringSimilarity.printSimilarity(it.name, hospital.name)
val similarity = StringSimilarity.similarity(it.name, hospital.name.toUpperCase())
if (similarity > SIMILARITY_THRESHOLD) {
Log.i(MTAG, "findNearbyOfficialHealthInstitutions() - ${it.name} and ${hospital.name.toUpperCase()} have %$similarity")
result.add(hospital)
}
}
}
Log.i(TAG, "------------------------------------------")
result.forEach {
Log.i(MTAG, "findNearbyOfficialHealthInstitutions() - hospital.name is ${it.name}")
}
return@async result
}.await()
}
【问题讨论】:
-
为什么不检查它是否为空并返回一个空列表呢?
-
是
addAllNearbyLocations异步吗? -
@m0skit0 它应该返回非空对象。检查空能力不是我在这里遇到的问题。真正的问题是,它首先不应该返回空值。
-
@Tenfour04 是正确的,它是异步的。要桥接使用回调和协程的旧异步代码,请检查suspendCoroutine。我会写一个全面的答案。
-
当某个库或 API 中的函数采用回调参数时,这是因为它在后台线程上运行一些代码,然后在完成时调用您的回调。这是异步的定义。因此,当您到达
deferred?.await()行时,尚未调用回调。正如@m0skit0 的回答所示,您可以使用suspendCoroutine将非协程异步库代码转换为挂起函数。
标签: android kotlin asynchronous coroutine kotlin-coroutines