# MutableStateFlow observe and change value from anywhere without creating a coroutine

**URL:** <https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799>\
**Category:** Language Design\
**Created:** [October 14, 2022, 3:25pm UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799 "2022-10-14T15:25:25Z")\
**Posts on this page:** 15\
**Page:** 2

<div class="post-metadata">

**Author:** ![gildor](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/gildor/32/1891_2.png) [@gildor](https://discuss.kotlinlang.org/u/gildor)\
**Post date:** [October 21, 2022, 6:41am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/22 "2022-10-21T06:41:49Z")

</div>

Could you show some real-life examples with LiveData. I just don’t understand the example above because you use StateFlow.value, which is not how you want to use it in real life

---

<div class="post-metadata">

**Author:** ![gildor](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/gildor/32/1891_2.png) [@gildor](https://discuss.kotlinlang.org/u/gildor)\
**Post date:** [October 21, 2022, 6:44am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/23 "2022-10-21T06:44:27Z")

</div>

I believe they didn’t mean “Observable” as particular class, but just any implementation of observable as a design pattern which suits your use case.

Also you can write composable adapter for any observable implementation.

But I still not quite sure what you try to implement, because in case of Composable you don’t need (and you should never rely at all) runBlocking and .value, because composable observes data using Flow adapter to convert it to composable sate, so no need to use value

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [October 24, 2022, 11:24am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/24 "2022-10-24T11:24:23Z")

</div>

Looks like we need to change `runBlocking` to something more optimized that `Composable` uses.

---

<div class="post-metadata">

**Author:** ![gildor](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/gildor/32/1891_2.png) [@gildor](https://discuss.kotlinlang.org/u/gildor)\
**Post date:** [October 25, 2022, 3:02am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/25 "2022-10-25T03:02:48Z")

</div>

Well, for this you need a test that uses Composable, you can for example write test with ComposeRunner Android test and use [collectAsState](https://developer.android.com/reference/kotlin/androidx/compose/runtime/package-summary#(kotlinx.coroutines.flow.StateFlow).collectAsState(kotlin.coroutines.CoroutineContext))

runBlocking + stateFlow.value is not what Composable is doing with stateFlow , it’s very different because composable actually uses stateFlow.collect() and uses stateFlow.value only for initial value, so no blocking or relying on value except for initial valyue

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [October 28, 2022, 10:16am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/26 "2022-10-28T10:16:09Z")

</div>

So, the question is: how to make this `stateFlow.collect()` within 1 line properly then? Extension is fine too.

---

<div class="post-metadata">

**Author:** ![gildor](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/gildor/32/1891_2.png) [@gildor](https://discuss.kotlinlang.org/u/gildor)\
**Post date:** [October 30, 2022, 6:36am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/27 "2022-10-30T06:36:22Z")

</div>

`stateFlow.collectAsState()`

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [November 4, 2022, 10:44am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/28 "2022-11-04T10:44:53Z")

</div>

I didn’t find: how can it be used outside of the composable in a plain class?

> [@gildor](#):
>
> stateFlow.collectAsState()

---

<div class="post-metadata">

**Author:** ![gildor](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/gildor/32/1891_2.png) [@gildor](https://discuss.kotlinlang.org/u/gildor)\
**Post date:** [November 10, 2022, 7:12am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/29 "2022-11-10T07:12:51Z")

</div>

You cannot, this is why I suggested above to use Android UI tests instead  
The problem with emulating compose with non-composable test (even with proper reactive code) is that compose its own, particular semantics for recomposition, so if you target Compose, use a real Compose test, not try to emulate it with stateFlow.value, because code on Compose and code with pure reactive streams for this would be pretty different

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [November 10, 2022, 8:00am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/30 "2022-11-10T08:00:17Z")

</div>

Why I should write my entire program in tests? It doesn’t work this way, I need a regular code solution. You missed something.

---

<div class="post-metadata">

**Author:** ![gildor](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/gildor/32/1891_2.png) [@gildor](https://discuss.kotlinlang.org/u/gildor)\
**Post date:** [November 10, 2022, 8:26am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/31 "2022-11-10T08:26:15Z")

</div>

Probably I misunderstood you.  
Your original code uses test to emulate this. Do not use test then, use regular Compose code

> We have `Compose` that can observe `StateFlow` without extra coroutines

Isn’t you said that you use compose. why now you want to use in a plain class?  
Anyway, if you want, you don’t need collectAsState, you need pure reactive solution

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [November 21, 2022, 11:10am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/32 "2022-11-21T11:10:39Z")

</div>

> [@gildor](#):
>
> Isn’t you said that you use compose. why now you want to use in a plain class?

Because it’s a bad practice to use calculations in View. At least, you need to use viewModel.

---

<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:** [November 21, 2022, 1:08pm UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/33 "2022-11-21T13:08:47Z")

</div>

Yes, calculations are in the model and the view observes the model for changes:

```kotlin
Model:

val up = 10

val bl = MutableStateFlow(3)
val bp = bl.map { it * 0.2f }
val ut = bp.map { (it * up).toInt() }

View:

ut.collectAsState(null)

```

This is really as simple as that. I still have problems following you and why do we need to complicate this with `runBlocking()`, `Flowable` wrappers and stuff.

Maybe the only tricky part here is that `bl` have immediate value and transformations are also immediate, so we could expect we should have immediate value for `ut` as well, but we don’t. This may be indeed counter-intuitive. We could either use `null` as above for an initial value (it should be immediately replaced with the proper value) or we could extract `ut` calculation to a separate function and call it here directly to get initial value.

---

<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:** [November 21, 2022, 1:15pm UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/34 "2022-11-21T13:15:33Z")

</div>

In the past I planned to create a library for Kotlin and Java that provides “reactive variables”, with Kotlin sweetness and adapters for flows and other reactive solutions. Then I realized it wouldn’t be that useful, because people already use flows and RxJava and even if my library would help with some use cases, that would be probably not enough to justify using an entirely new tool. I stopped working on this.

Maybe I miss some use scenario that would make such a tool useful and you have this exactly scenario. But frankly, I still have problems following you and your case.

---

<div class="post-metadata">

**Author:** ![gildor](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/gildor/32/1891_2.png) [@gildor](https://discuss.kotlinlang.org/u/gildor)\
**Post date:** [November 23, 2022, 6:24am UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/35 "2022-11-23T06:24:19Z")

</div>

> Because it’s a bad practice to use calculations in View

This is not what I propose, your reactive Flows (and mapping code) must be on side of VM/any other business abstraction and consumption of final result must be on side of composable with collectAsState or just simple flow.collect{}, @broot explained it really well.  
My point was about the usage of collectAsState which is not the same as runBlocking and stateFlow.value

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [February 28, 2023, 8:08pm UTC](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799/36 "2023-02-28T20:08:07Z")

</div>

So, I tried another wrapper and it shown even worse performance.

```auto
class Flowable2<T>(val flow: Flow<T>, initial: T) {
    var value: T = initial
        private set

    private val coroutineScope = CoroutineScope(Dispatchers.Default)

    init {
        coroutineScope.launch {
            flow.collect {
                value = it
            }
        }
    }
}

```

The best solution as for now I have is:

```
val <T> Flow<T>.value: T get() = runBlocking { this@value.first() }

@Test
fun performanceBlocking(){
    val counts = 100000
    val fl = MutableStateFlow(2)
    val a = fl.map { it }
    var b = 0

    val timeElapsed = measureTimeMillis {
        repeat(counts) { b += a.value }
    }

    println("$timeElapsed, $b")
    b = 0

    val timeElapsed2 = measureTimeMillis {
        repeat(counts) { b += fl.value }
    }
    println("$timeElapsed2, $b")

    assertTrue { timeElapsed <= timeElapsed2 }
}

```

Shows 900 ms vs 1 ms

I just need to change `runBlocking` to something synchronous but not sure what.

[Previous page](https://discuss.kotlinlang.org/t/mutablestateflow-observe-and-change-value-from-anywhere-without-creating-a-coroutine/25799.md?page=1)
