'Suspend function 'callGetApi' should be called only from a coroutine or another suspend function
I am calling suspended function from onCreate(...)
override fun onCreate(savedInstanceState: Bundle?) {
...
...
callGetApi()
}
and the suspended function is:-
suspend fun callGetApi() {....}
But the error shows up Suspend function 'callGetApi' should be called only from a coroutine or another suspend function
Solution 1:[1]
Suspend function should be called only from a coroutine.
That means to call a suspend
function you need to use a coroutine builder, e.g. launch
, async
or runBlocking
(recommended to use only in unit tests). For example:
class Activity : AppCompatActivity(), CoroutineScope {
private var job: Job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
launch {
val result = callGetApi()
onResult(result) // onResult is called on the main thread
}
}
suspend fun callGetApi(): String {...}
fun onResult(result: String) {...}
}
To use Dispatchers.Main
in Android add dependency to the app's build.gradle
file:
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1'
The MOST RECENT APPROACH would be to use extension properties in ViewModel
and Activity
/Fragment
:
In
ViewModel
we can useviewModelScope
to launch a coroutine:viewModelScope.launch { ... }
It attached to the lifecycle of Activity/Fragment
and cancels launched coroutines when they destroyed.
- Similar in
Activity/Fragment
we can use the following extension properties to launch a coroutine:lifecycleScope.launch {}
,lifecycle.coroutineScope.launch {}
,viewLifecycleOwner.lifecycleScope.launch {}
(applicable inFragments
).
Solution 2:[2]
Looks like the most elegant way to do it as of July 2019, is the one described here:
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
class Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super...
lifecycleScope.launch {
val result = callGetApi()
onResult(result)
}
}
}
Don't forget to add the correponding lib:
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-alpha02"
Solution 3:[3]
The above answer worked , but i solved it without inheriting CoroutineScope
class by just using ....
gradle.build
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
}
Activity.kt
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Dispatchers
GlobalScope.launch (Dispatchers.Main) { callGetApi() }
Dispatchers.Main
is important cause you cannot update the UI in any other thread than main.
But its recommended to inherit CoroutineScope to maintain the lifecycle of the activity and onDestroy
of the activity to kill the job
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | hannes ach |
Solution 3 |