Reputation: 1677
I have created function as below :
fun getPercentage(id:String): String {
var percentage=""
scope.launch {
percentage=repo.getPercentage(id)?.get(0)?.percent.toString()
Log.e("$$$ value >>","$$$ value >>"+percentage)
}
Log.e("$$$ value outside >>","$$$ value >>"+percentage)
return percenatge
}
Here, I can not return the updated value using the varibale : percentage.
Logs I am getting is as below :
$$$ value outside >>
$$$ value >> 50
means I can't return the latest value. something going wrong with the flow.
Someone suggested me to use async{} and await(). But I don't know How it will be helpful here?
Please guide. Thanks.
Upvotes: 5
Views: 9811
Reputation: 19685
The getPercentage
function creates a coroutine in the background via the launch function, and then continues without waiting. Your "outside" code is therefore running before the "inner" coroutine completes.
The first option is to use the async function instead to return a Deferred value from the coroutine:
fun getPercentage(id:String): Deferred<String> {
return scope.async {
percentage=repo.getPercentage(id)?.get(0)?.percent.toString()
Log.e("$$$ value >>","$$$ value >>"+percentage)
}
}
Note of course that its more likely you want to make getPercentage
a suspend function, and then call await
directly:
suspend fun getPercentage(id:String): String {
val percentageDeferred = scope.async {
percentage=repo.getPercentage(id)?.get(0)?.percent.toString()
Log.e("$$$ value >>","$$$ value >>"+percentage)
}
val percentage = percentageDeferred.await()
Log.e("$$$ value outside >>","$$$ value >>"+percentage)
return percentage
}
It's also likely you want to do something else before the await
otherwise you're probably just better off making repo.getPercentage
a suspend function as well, and calling it directly:
suspend fun getPercentage(id:String): String {
// if repo.getPercentage is a suspend function, this call suspends
// like the await in the previous example
val percentage = repo.getPercentage(id)?.get(0)?.percent.toString()
Log.e("$$$ value outside >>","$$$ value >>"+percentage)
return percentage
}
See Concurrent using async in the Kotlin docs.
Upvotes: 8
Reputation: 1689
I don't believe you necessarily need to use async in this case, particularly. You only need to be aware that whatever is inside launch { ... }
is executed asynchronously. So by the time getPercentage
returns, your coroutine may not have even started yet.
Keeping that in mind, I believe you may want to change the way your code works. The only way you can make fun getPercentage(id: String): String
work without changing that signature is by replacing scope.launch { ... }
with scope.runBlocking { ... }
, but you probably don't want to do that, because it would block your thread.
Instead, you might change getPercentage
to be a suspend
method:
suspend fun getPercentage(id: String): String {
return repo.getPercentage(id)?.get(0)?.percent.toString()
}
However, suspend
methods can only be called from inside a coroutine. So you would need to call it like this:
scope.launch {
val percentage = getPercentage("some ID")
// Now you can use `percentage` for whatever you need.
}
Upvotes: 3