Kotlin/Native error: Entry point can not be a suspend function - kotlin

When I use Kotlin Coroutines in a Kotlin/JVM project I can add the suspend keyword to the main entry of the program.
import kotlinx.coroutines.*
suspend fun main() {
doWorld()
}
suspend fun doWorld() = coroutineScope {
launch {
delay(1000L)
println("World!")
}
println("Hello")
}
Run example in Kotlin Playground
However, when I use the same code in a Kotlin Native project, I get an error at runtime
e: Entry point can not be a suspend function.
I have found a YouTrack issue requesting suspend fun main() support in Kotlin Native.
Until the feature is available, what is the equivalent to suspend fun main() in Kotlin Native?
I'm using
Kotlin/Native v1.7.22
Kotlinx Coroutines 1.6.4

try this code...
import kotlinx.coroutines.*
fun main() {
runBlocking {
doWorld()
}
}
suspend fun doWorld() = coroutineScope {
launch {
delay(1000L)
println("World!")
}
println("Hello")
}
You need to call doWorld() method from anyother coroutine or have to make suspend function. The purpose is to change any thread to Main-thread.

Related

avoid Error Suspension functions can be called only within coroutine body Kotlin [duplicate]

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
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 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).
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"
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

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

Hi am trying to run following kotlin code:
Code Snippet 1
This is not working
with the error:
function 'delay' should be called only from a coroutine or another suspend function
package kotlinx.coroutines.guide.exampleBasic02
import kotlinx.coroutines.*
fun main() = runBlocking { // this: CoroutineScope
launch {echoWorldWrapper() }
println("Hello")
}
suspend fun echoWorldWrapper() {
echoWorld()
}
fun echoWorld() {
delay(1000L)
println("World!")
}
However following works:
Code Snippet 2:
package kotlinx.coroutines.guide.exampleBasic02
import kotlinx.coroutines.*
fun main() = runBlocking { // this: CoroutineScope
launch {echoWorldWrapper() }
println("Hello")
}
suspend fun echoWorldWrapper() {
delay(1000L)
println("World!")
}
In my production code I can only follow Code Snippet 1. Is there any workaround for approach 1 to work. I am new to Kotlin and couldn't find any other answer to this question. Thanks.
It is not possible to call a suspend function from a function that is not also a suspend function. suspend carries with it under the hood the state of a coroutine in a Continuation object. delay() cannot operate without that coroutine to work with.
The functionality of delay() is to suspend a coroutine for a period of time and then resume it. It doesn't make any sense for it to be called from a non-suspend function, because that means there is no coroutine to suspend.
The alternative for a non-suspend function is to use Thread.sleep(), which will block the thread for a period of time. Example:
//Use withContext to make it acceptable to call a blocking function in a coroutine
suspend fun echoWorldWrapper() = withContext(Dispatchers.IO) {
echoWorld()
}
// A blocking function:
fun echoWorld() {
Thread.sleep(1000L)
println("World!")
}

Launch gives a compliation error in Kotlin

I was trying out a few things in Kotlin. The launch in the following code gives a compilation error. However, the GlobalScope.launch works and giving launch inside runBlocking also work.
fun main() {
launch{
} }
If you see the definition of the launch:
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job (source)
It is an extension function to the CoroutineScope, so it must be called on a CoroutineScope.
If you use the runBlocking, it'll give you a CoroutineScope as this variable in the block, so launch implicitly is this.launch.
In order to launch a coroutine it must have a lifecycle Job and a CoroutineDispatcher, which is contained in the CoroutineContext inside the CoroutineScope.
So if you want the coroutine, there is two common practise:
runBlocking (single-threaded start).
fun main() = runBlocking { // this: CoroutineScope
launch {} // implicit this.launch {}
}
coroutineScope factory function (starts at main thread but switches to default dispatcher when needed).
suspend fun main() = coroutineScope { // this: CoroutineScope
launch {} // implicit this.launch {}
}

How to launch a Kotlin coroutine in a `suspend fun` that uses the current parent Scope?

How can I launch a coroutine from a suspend function and have it use the current Scope? (so that the Scope doesn't end until the launched coroutine also ends)
I'd like to write something like the following –
import kotlinx.coroutines.*
fun main() = runBlocking { // this: CoroutineScope
go()
}
suspend fun go() {
launch {
println("go!")
}
}
But this has a syntax error: "Unresolved Reference: launch". It seems launch must be run in one of the following ways –
GlobalScope.launch {
println("Go!")
}
Or
runBlocking {
launch {
println("Go!")
}
}
Or
withContext(Dispatchers.Default) {
launch {
println("Go!")
}
}
Or
coroutineScope {
launch {
println("Go!")
}
}
None of these alternatives does what I need. Either the code "blocks" instead of "spawning", or it spawns but the parent scope won't wait for its completion before the parent scope itself ends.
I need it to "spawn" (launch) in the current parent coroutine scope, and that parent scope should wait for the spawned coroutine to finish before it ends itself.
I expected that a simple launch inside a suspend fun would be valid and use its parent scope.
I'm using Kotlin 1.3 and cotlinx-coroutines-core:1.0.1.
You should make the function go an extension function of CoroutineScope:
fun main() = runBlocking {
go()
go()
go()
println("End")
}
fun CoroutineScope.go() = launch {
println("go!")
}
Read this article to understand why it is not a good idea to start in a suspend functions other coroutines without creating a new coroutineScope{}.
The convention is: In a suspend functions call other suspend functions and create a new CoroutineScope, if you need to start parallel coroutines. The result is, that the coroutine will only return, when all newly started coroutines have finished (structured concurrency).
On the other side, if you need to start new coroutines without knowing the scope, You create an extensions function of CoroutineScope, which itself it not suspendable. Now the caller can decide which scope should be used.
I believe I found a solution, which is with(CoroutineScope(coroutineContext). The following example illustrates this –
import kotlinx.coroutines.*
fun main() = runBlocking {
go()
go()
go()
println("End")
}
suspend fun go() {
// GlobalScope.launch { // spawns, but doesn't use parent scope
// runBlocking { // blocks
// withContext(Dispatchers.Default) { // blocks
// coroutineScope { // blocks
with(CoroutineScope(coroutineContext)) { // spawns and uses parent scope!
launch {
delay(2000L)
println("Go!")
}
}
}
However, Rene posted a much better solution above.
Say you are dealing with some RxJava Observable and it isn't the time to refactor them, you can now get a hold of a suspend function's CoroutineScope this way:
suspend fun yourExtraordinarySuspendFunction() = coroutineScope {
val innerScope = this // i.e. coroutineScope
legacyRxJavaUggh.subscribe { somePayloadFromRxJava ->
innerScope.launch {
// TODO your extraordinary work
}
}
}

Cannot execute kotlin coroutine (no such method exception

I took this simple code snippet from kotlin examples:
fun main(args: Array<String>) = runBlocking<Unit> {
withTimeout(1300L) {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
}
}
When I try to run it, it throws
java.lang.NoSuchMethodError: kotlinx.coroutines.experimental.ScheduledKt.withTimeout$default(JLjava/util/concurrent/TimeUnit;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Ljava/lang/Object;
I use kotlinVersion = '1.1.51'
Any advice?
In your case, make sure that in your build.gradle file you enable coroutines :
kotlin {
experimental {
coroutines "enable"
}
}
Also you should trigger your coroutine with launch(UI) and call explicitly wait() and the suspended methods. The rest of your code will be executed on the UI thread.
Hope it resolved your issue!