Suspend function 'callGetApi' should be called only from a coroutine or another suspend function

AndroidKotlinKotlin CoroutinesCoroutineCoroutinescope

Android Problem Overview


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

Android Solutions


Solution 1 - Android

> 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:

It attached to the lifecycle of Activity/Fragment and cancels launched coroutines when they destroyed.

Solution 2 - Android

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 - Android

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSantanu SurView Question on Stackoverflow
Solution 1 - AndroidSergeyView Answer on Stackoverflow
Solution 2 - AndroidKiprView Answer on Stackoverflow
Solution 3 - AndroidSantanu SurView Answer on Stackoverflow