Reputation: 268
Code changes applied.
I followed a guide on how to create a kotlin coroutine and do network request and ended up with:
suspend fun <T : Any> safeApiCall(call: suspend () -> Response<T>): ApiResult<T> {
return safeApiResult(call)
}
private suspend fun <T: Any> safeApiResult(call: suspend ()-> Response<T>) : ApiResult<T>{
val response = call.invoke()
return if (response.isSuccessful) {
val body = response.body()
if (body == null) {
ApiResult.Error(response.code())
} else {
ApiResult.Success(body)
}
} else {
ApiResult.Error(response.code())
}
}
suspend fun getSnappedPoints(path: String): ApiResult<SnappedPointsData> {
return safeApiCall(
call = { googleRoadsService.getSnappedPoints(path).await()}
)
}
and calling the network request looks like this:
private fun getSnappedPoints() {
val paths = Utils.getPathFromLocations(locations)
CoroutineScope(Dispatchers.IO).launch {
val results = paths.map {
async { googleRoadsRepository.getSnappedPoints(it) }
}.awaitAll()
Timber.i("results: ${results.size}")
val snappedPoints = ArrayList<LocationSnap>()
results.forEach {
if (it is ApiResult.Success) {
snappedPoints.addAll(it.data.snappedPoints)
}
}
withContext(Dispatchers.Main) {
if (snappedPoints.isNotEmpty()) {
drawPolyline(snappedPoints)
} else {
showError()
}
}
}
}
Current problem:
The function getSnappedPoints()
is called when I click on specific item. For the very first time it actually calls google API and result is > 0 (size), but if I go back and click second time on the same/other item, getSnappedPoints()
is called, paths
is not Empty, but somehow it does not call googleRoadsRepository.getSnappedPoints(it)
and kinda skips that step in debug and all I can see is that result is always 0. What could cause this?
Upvotes: 2
Views: 13835
Reputation: 1320
While you at IO thread so what is the necessity of using async + await
? At the IO scope, you are free to suspend and wait for the response.
Try this one and notify me to know what will the result?
private fun getSnappedPoints() {
val paths = Utils.getPathFromLocations(locations)
CoroutineScope(Dispatchers.IO).launch {
val results = paths.map {
googleRoadsRepository.getSnappedPoints(it)
}
// rest of you code...
}
Upvotes: 0
Reputation: 1849
Each coroutine (launch
) is a unit of concurrency, if you want to run each request concurrently, you'll have to do a launch
/async
for each concurrent request.
private fun getPoints() {
val multipleParams = Utils.getArrayListOfParams()
coroutineJob = CoroutineScope(Dispatchers.IO).launch {
val results = multipleParams.map {
async { Repository.getPoints(it) }
}.awaitAll()
// Do something with results, once all have been gotten.
// result and result2, result[it] has finished, continue)
}
}
Bonus:
CoroutineScope
without cancelling it, then you should use GlobalScope
as an optimisation. (Like so GlobalScope.launch(Dispatchers.IO)
)Dispatchers.IO
to do this, since it appears you are not blocking the coroutine/thread. Dispatchers.Default
will do just fine.coroutineJob
variable for but it looks suspicious.Upvotes: 2