I'm using nested Coroutine blocks in my code. And I'm getting a null value when I tried to get Deferred type's result to a variable. Thus, It causes a casting problem which is kotlin.TypeCastException: null cannot be cast to non-null type kotlin.collections.ArrayList in getNearbyHealthInstitutions() method's return line. I believe, I did the right implementation at some point but what am I missing to get null value from Deferred's result? The funny thing is when I debug it, it does return the expected value. I think it should be the concurrency problem or I don't have any idea why it works in debug mode in the first place. Any ideas fellas?
// 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
asynchronous? – Animesh Sahudeferred?.await()
, the callback has not been called yet. You can convert non-coroutine asynchronous library code into a suspend function usingsuspendCoroutine
as @m0skit0's answer shows. – Tenfour04