Second coroutine is never executed - kotlin

I have two coroutines inside another one, it's supposed that both inner coroutines are going to execute asynchronously, but this doesn't happened. The second one waits until the first finish.
This is my code:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
var flag = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runBlocking {
launch {
printOne()
}
launch {
printTwo()
}
}
}
suspend fun printOne() {
while (flag == false)
Log.e("log", "111111")
}
suspend fun printTwo() {
Log.e("log", "222222")
Log.e("log", "222222")
Log.e("log", "222222")
Log.e("log", "222222")
flag = true
}
}
I assumed that the code inside the first launch{} would execute in a thread separately from the code in the second launch{} as well as any other corutine. But it keeps looping for ever inside the first launch{}

Is Log.e a suspend function? If not, then your first coroutine never calls another suspend function, and never explicitly yields, so it never gives other coroutines a chance to run on the same thread.
The call to runBlocking is using a default dispatcher that uses only one thread, so there's no thread available to run the second coroutine.
You could fix this by explicitly yielding after every loop iteration:
suspend fun printOne() {
while (flag == false) {
Log.e("log", "111111")
yield() // <-- give other coroutines a turn
}
}
If you try to fix the problem by using a different dispatcher (like runBlocking(Dispatchers.IO)), you may notice another problem...
The flag variable is not volatile. Changes to the variable made by a coroutine running in one thread might not be seen by cooroutines in a different thread for a long time, if ever. You could fix this by annotating the property as volatile:
#Volatile
var flag = false

Coroutines are not threads. You can set them to run in different threads if you want, using Dispatchers, but if not, you have to let execution time for other coroutines in the same thread with yield() or delay(Long).

You are using runBlocking. Replace it for lifecycleScope.launch.
The Android library for activities/fragment added a coroutine launcher tied to the lifecycle.

I think you can get your answer with this simple example
suspend fun printOne() {
println( "111111")
delay(200)
println( "111111")
delay(200)
println( "111111")
delay(200)
println( "111111")
delay(200)
println( "111111")
delay(200)
println( "111111")
delay(200)
println( "111111")
delay(200)
println( "111111")
delay(200)
}
suspend fun printTwo() {
println( "222222")
delay(100)
println( "222222")
delay(100)
println( "222222")
delay(100)
println( "222222")
delay(100)
}

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

Kotlin Coroutines: what's the diffrence between using NonCancellable and a standalone new Job

In Coroutines, when I want to guard a block of code against cancellation, I should add NonCancellable to the Context:
#Test
fun coroutineCancellation_NonCancellable() {
runBlocking {
val scopeJob = Job()
val scope = CoroutineScope(scopeJob + Dispatchers.Default + CoroutineName("outer scope"))
val launchJob = scope.launch(CoroutineName("cancelled coroutine")) {
launch (CoroutineName("nested coroutine")) {
withContext(NonCancellable) {
delay(1000)
}
}
}
scope.launch {
delay(100)
launchJob.cancel()
}
launchJob.join()
}
}
The above unit test will take ~1.1sec to execute, even though the long-running Coroutine is cancelled after just 100ms. That's the effect of NonCancellable and I understand this point.
However, the below code seems to be functionally equivalent:
#Test
fun coroutineCancellation_newJobInsteadOfNonCancellable() {
runBlocking {
val scopeJob = Job()
val scope = CoroutineScope(scopeJob + Dispatchers.Default + CoroutineName("outer scope"))
val launchJob = scope.launch(CoroutineName("cancelled coroutine")) {
launch (CoroutineName("nested coroutine")) {
withContext(Job()) {
delay(1000)
}
}
}
scope.launch {
delay(100)
launchJob.cancel()
}
launchJob.join()
}
}
I tried to find any functional differences between these two approaches in terms of cancellation, error handling and general functionality, but so far I found none. Currently, it looks like NonCancellable is in the framework just for readability.
Now, readability is important, so I'd prefer to use NonCancellable in code. However, its documentation makes it sound like it is, in fact, somehow different from a regular Job, so I want to understand this aspect in details.
So, my quesiton is: is there any functional difference between these two approaches (i.e. how can I modify these unit tests to have difference in outcomes)?
Edit:
Following Louis's answer I tested "making cleanup non-cancellable" scenario and in this case Job() also works analogous to NonCancellable. In the below example, unit test will run for more than 1sec, even though the coroutine is cancelled just after 200ms:
#Test
fun coroutineCancellation_jobInsteadOfNonCancellableInCleanup() {
runBlocking {
val scope = CoroutineScope(Job() + Dispatchers.Default + CoroutineName("outer scope"))
val launchJob = scope.launch(CoroutineName("test coroutine")) {
try {
delay(100)
throw java.lang.RuntimeException()
} catch (e: Exception) {
withContext(Job()) {
cleanup()
}
}
}
scope.launch {
delay(200)
launchJob.cancel()
}
launchJob.join()
}
}
private suspend fun cleanup() {
delay(1000)
}
NonCancellable doesn't respond to cancellation, while Job() does.
NonCancellable implements Job in a custom way, and it doesn't have the same behavior as Job() that is using cancellable implementation.
cancel() on NonCancellable is no-op, unlike for Job() where it would cancel any child coroutine, and where any crash in the child coroutines would propagate to that parent Job.

function inside coroutine scope is not cancelled

Trying to grasp coroutines. I have an expectation that this code shouldn't print anything. However, it prints "work done" so cancellation didn't do a thing. How is it so?
suspend fun foo() = coroutineScope {
launch { doSomeWork() }
}
suspend fun doSomeWork() {
delay(10000)
println("Work done")
}
suspend fun main() {
val fooResult = foo()
fooResult.cancel()
}
I finally got it. The main coroutine suspends on "coroutineScope" call, that's why

Kotlin coroutines not running launch on main

I have following code:
Timber.d("Calling coroutine from thread: ${Thread.currentThread().name}")
scope.launch {
Timber.d("Current thread: ${Thread.currentThread().name}")
runTest()
}
suspend fun runTest() {
coroutineScope {
launch(Dispatchers.Main) {
Timber.d("Running from thread: ${Thread.currentThread().name}")
}
}
}
If I run it. App crashes with no error in log.
In my log I see:
Calling coroutine from thread: main
Current thread: DefaultDispatcher-worker-2
But I don't see entry with Running from thread:
This is done in viewmodel
My scope looks like this:
val scope: ViewModelCoroutineScope = ViewModelCoroutineScope(Dispatchers.Default)
class ViewModelCoroutineScope(
context: CoroutineContext
) : CoroutineScope {
private var onViewDetachJob = Job()
override val coroutineContext: CoroutineContext = context + onViewDetachJob
fun onCleared() {
onViewDetachJob.cancel()
}
}
What am I doing wrong?
Moving to a different machine I finally got some errors about Dispatchers.MAIN not working.
In the end all I had to do was replace all raw coroutine dependencies with:
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1")

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