# Why does emit() cancel this coroutine?

**URL:** <https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153>\
**Category:** Support\
**Created:** [October 7, 2021, 5:39pm UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153 "2021-10-07T17:39:06Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![AndreKR](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrekr/32/8901_2.png) [@AndreKR](https://discuss.kotlinlang.org/u/AndreKR)\
**Post date:** [October 7, 2021, 5:39pm UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/1 "2021-10-07T17:39:06Z")

</div>

This code works, I see a toast with “ping” every 5 seconds:

```kotlin
class DatesViewModel(private val appl: Application) : AndroidViewModel(appl) {
    val dates: LiveData<String> = liveData {
        viewModelScope.launch {
            try {
                while(true) {
                    delay(5_000)
                    Toast.makeText(appl, "ping", Toast.LENGTH_SHORT).show()
                }
            } catch (e: Exception) {
                Log.d("E", e.toString())
            }
        }
        emit("foo")
    }
}

```

But this does not:

```kotlin
class DatesViewModel(private val appl: Application) : AndroidViewModel(appl) {
    val dates: LiveData<String> = liveData {
        viewModelScope.launch {
            try {
                while(true) {
                    delay(5_000)
                    emit("bar") // This is the only changed line
                    Toast.makeText(appl, "ping", Toast.LENGTH_SHORT).show()
                }
            } catch (e: Exception) {
                Log.d("E", e.toString())
            }
        }
        emit("foo")
    }
}

```

The value “bar” is never actually emitted. I don’t see a single “ping” toast. The `Log` line logs:

> ```auto
> D/E: kotlinx.coroutines.JobCancellationException: StandaloneCoroutine has completed normally; job=StandaloneCoroutine{Completed}@c3e4ddf
> 
> ```

Why does this happen and how shall I prevent it?

I was expecting the coroutine to be cancelled only when the ViewModel is cleared.

---

<div class="post-metadata">

**Author:** ![AndreKR](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrekr/32/8901_2.png) [@AndreKR](https://discuss.kotlinlang.org/u/AndreKR)\
**Post date:** [October 7, 2021, 5:55pm UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/2 "2021-10-07T17:55:13Z")

</div>

I think I know what is going on. This is the source of `emit()`:

```kotlin
    override suspend fun emit(value: T) = withContext(coroutineContext) {
        target.clearSource()
        target.value = value
    }

```

My _guess_ is that `coroutineContext` was cancelled (ended) when the `liveData { ... }` block ended, so trying to run something `withContext(coroutineContext)` throws a `JobCancellationException`?

I don’t know how to make it work though. `emit()` seems to be the only way to publish a new value to `target`.

---

<div class="post-metadata">

**Author:** ![AndreKR](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrekr/32/8901_2.png) [@AndreKR](https://discuss.kotlinlang.org/u/AndreKR)\
**Post date:** [October 7, 2021, 6:10pm UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/3 "2021-10-07T18:10:11Z")

</div>

The solution was so simple it hurts. Why launch another coroutine and let the first one end. Just keep the first one alive:

```kotlin
class DatesViewModel(private val appl: Application) : AndroidViewModel(appl) {
    val dates: LiveData<String> = liveData {
        emit("foo")
        while(true) {
            delay(5_000)
            emit("bar")
            Toast.makeText(appl, "ping", Toast.LENGTH_SHORT).show()
        }
    }
}

```

Another alternative might have been to create another `LiveData` or `Flow`, emit that with `emitSource` and then update that one.

It was [this](https://stackoverflow.com/questions/58245708/how-to-call-again-livedata-coroutine-block/58666215#58666215) answer that made me think of the solution.

---

<div class="post-metadata">

**Author:** ![broot](https://avatars.discourse-cdn.com/v4/letter/b/a88e57/32.png) [@broot](https://discuss.kotlinlang.org/u/broot)\
**Post date:** [October 7, 2021, 6:13pm UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/4 "2021-10-07T18:13:26Z")

</div>

Why do you `launch()` a new coroutine using `viewModelScope`? I’m not 100% sure what is going on here, but it doesn’t seem right. By doing this the coroutine that is used to `emit()` to the flow does not know there is another coroutine that tries to emit. After emitting “foo” the coroutine finishes and the flow itself is also considered completed. Then “bar” can’t be emitted.

---

<div class="post-metadata">

**Author:** ![AndreKR](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrekr/32/8901_2.png) [@AndreKR](https://discuss.kotlinlang.org/u/AndreKR)\
**Post date:** [October 7, 2021, 7:49pm UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/5 "2021-10-07T19:49:54Z")

</div>

You were 3 minutes too late but spot on. 🙂

---

<div class="post-metadata">

**Author:** ![AndreKR](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrekr/32/8901_2.png) [@AndreKR](https://discuss.kotlinlang.org/u/AndreKR)\
**Post date:** [October 10, 2021, 1:14am UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/6 "2021-10-10T01:14:03Z")

</div>

Ok, I just found out that this is _not_ the solution, at least not like this.

5 seconds after the last observer of the `LiveData` goes away, the coroutine is cancelled and then restarted when another observer comes. So even though the ViewModel’s Lifecycle didn’t end, this code essentially discards the data and starts a fresh recalculation every time the observer goes away for more than 5 seconds. This is not what I want.

---

<div class="post-metadata">

**Author:** ![nickallendev](https://avatars.discourse-cdn.com/v4/letter/n/cdc98d/32.png) [@nickallendev](https://discuss.kotlinlang.org/u/nickallendev)\
**Post date:** [October 10, 2021, 6:07am UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/7 "2021-10-10T06:07:49Z")

</div>

That’s how `liveData` builder is designed to work so it doesn’t use resources while no one is listening. Just create your `LiveData` directly and launch with the lifetime you want.

```auto
class DatesViewModel(private val appl: Application) : AndroidViewModel(appl) {
    val dates: LiveData<String> = MutableLiveData(“foo”).also {
        viewModelScope.launch {
            while(true) {
                delay(5_000)
                it.setValue("bar")
                Toast.makeText(appl, "ping", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

```

---

<div class="post-metadata">

**Author:** ![AndreKR](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrekr/32/8901_2.png) [@AndreKR](https://discuss.kotlinlang.org/u/AndreKR)\
**Post date:** [October 10, 2021, 5:27pm UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/8 "2021-10-10T17:27:07Z")

</div>

Works perfectly.

---

<div class="post-metadata">

**Author:** ![AndreKR](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrekr/32/8901_2.png) [@AndreKR](https://discuss.kotlinlang.org/u/AndreKR)\
**Post date:** [October 11, 2021, 12:01am UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/9 "2021-10-11T00:01:14Z")

</div>

Well, actually not perfectly perfectly… I didn’t realize that at first.

It would be better if the _updating_ would indeed be cancelled, but the last data would be held.

So as long as there are observers, I see the “ping” toasts and “bar” is emitted. When the observer goes away, the “ping” toasts stop. But when the observer comes back, it immediately sees “bar”.

My solution fulfilled only the first part (the “ping” toasts stop) and yours fulfills only the second part (when the observer comes back, it immediately sees “bar”).

---

<div class="post-metadata">

**Author:** ![AndreKR](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrekr/32/8901_2.png) [@AndreKR](https://discuss.kotlinlang.org/u/AndreKR)\
**Post date:** [October 11, 2021, 4:05pm UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/10 "2021-10-11T16:05:37Z")

</div>

Now this is the final (hopefully) solution:

```kotlin
class DatesViewModel(private val appl: Application) : AndroidViewModel(appl) {
    val dates: LiveData<String?> = liveData {
        while(true) {
            if (latestValue == null) {
                emit("bar")
                Toast.makeText(appl, "ping", Toast.LENGTH_SHORT).show()
            }
            delay(5_000)
        }
    }
}

```

I removed the `emit("foo")` because “foo” was just my loading state. Now I represent the loading state by `null`. For this I changed `LiveData<String>` into `LiveData<String?>`.

Also I’m using `latestValue == null` to check whether we already emitted data before. The documentation of `latestValue` actually says:

> You can use this value to check what was then latest value `emit`ed by your `block` before it got cancelled.

---

<div class="post-metadata">

**Author:** ![brill](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/brill/32/7370_2.png) [@brill](https://discuss.kotlinlang.org/u/brill)\
**Post date:** [October 12, 2021, 1:13pm UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/11 "2021-10-12T13:13:34Z")

</div>

This is a very wrong way to use a ViewModel.

A ViewModel should **never** reverence UI elements, _including a toast_.  
There is quite a lot wrong with this code, but the very minimum thing to fix is that the UI should be observing the LiveData object in the fragment, to show the toast. It should not happen in the ViewModel. That’s the entire point of an observable ViewModel.

Your basic issue is that you have a coroutine inside a coroutine.  
The outer one has the emit() function, but it looks to me like you are allowing it to finish while the inner coroutine is still running.

Using the view model properly would prevent this from happening.

- Get rid of the `viewModelScope.launch {}` coroutine, the `liveData {}` is already a coroutine.
- viewModel.dates.observe(owner){ value:String? → Toast.makeText(appl, “ping”, Toast.LENGTH\_SHORT).show() }

---

<div class="post-metadata">

**Author:** ![AndreKR](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrekr/32/8901_2.png) [@AndreKR](https://discuss.kotlinlang.org/u/AndreKR)\
**Post date:** [October 12, 2021, 7:25pm UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/12 "2021-10-12T19:25:32Z")

</div>

The Toast is there to show me whether the coroutine is still running when there is no observer. It’s just debug code to help me understand how the logic works. It’s not part of the actual application. I should have made that more clear.

---

<div class="post-metadata">

**Author:** ![AndreKR](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/andrekr/32/8901_2.png) [@AndreKR](https://discuss.kotlinlang.org/u/AndreKR)\
**Post date:** [November 19, 2021, 10:44pm UTC](https://discuss.kotlinlang.org/t/why-does-emit-cancel-this-coroutine/23153/13 "2021-11-19T22:44:37Z")

</div>

Argh, this thing follows me around. Turns out my last solution still does not work properly.

Basically I have three different cases how the lambda can be called:

| | |
| --- | --- |
| ViewModel freshly created | Calculate and emit a value |
| Coroutine restarted after having been stopped | Do nothing |
| Delay expired | Calculate and emit a fresh value |

So here is the new new solution that hopefully covers all three cases:

```kotlin
class DatesViewModel(private val appl: Application) : AndroidViewModel(appl) {
    val dates: LiveData<String?> = liveData {
        while(true) {
            if (latestValue != null) {
                delay(5_000)
            }
            emit("bar")
            Toast.makeText(appl, "ping", Toast.LENGTH_SHORT).show()
        }
    }
}

```
