Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 890
Santanu Sur Avatar asked Dec 26 '18 07:12

Santanu Sur


People also ask

Can you run a suspend function outside of coroutine?

The syntax of a suspending function is similar to that of a regular function except for the addition of the suspend keyword. It can take a parameter and have a return type. However, suspending functions can only be invoked by another suspending function or within a coroutine.

How does coroutine suspension work?

With coroutines, it just suspends and gives the library a continuation with the instruction "Once you've got this data, just send it to the resume function". Then the thread can go do other things. Once the data is there, the thread will be used to resume from the point where the coroutine was suspended.

Can coroutines be suspended and resumed?

Coroutines can suspend themselves, and the dispatcher is responsible for resuming them. To specify where the coroutines should run, Kotlin provides three dispatchers that you can use: Dispatchers. Main - Use this dispatcher to run a coroutine on the main Android thread.

When should you not use coroutines?

Answer: a. You should not use them for any foreground task.


2 Answers

Suspend function should be called only from coroutine. That means you need to use a coroutine builder, e.g. launch. 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 BETTER APPROACH would be to use extension properties in ViewModel and Activity/Fragment:

  • In ViewModel we can use viewModelScope 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 in Fragments).
like image 102
Sergey Avatar answered Sep 19 '22 15:09

Sergey


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" 
like image 44
Kipr Avatar answered Sep 21 '22 15:09

Kipr