MutableStateFlow for methods (or how to make an observable function)?

I’m trying to make my methods reactive to update the view in Compose. But it’ll be too easy to be simple. The alternative is to try delegates but I need to implement it in my interface. How to do it properly?

interface Foo{
  fun foo(): MutableStateFlow<Int> = MutableStateFlow(bar() * chad())
}

//@Composable
val foo by xyz.foo().collectAsState()

Currently I made a hack: logging the variable that is used for calculations (like common status update). But it’s not good.

Suppose, the best but longest way is to observe all variables participated in the method and then provide a final observable variable. But it doesn’t work in interfaces.

So, let’s get our method
fun foo(): MutableStateFlow<Int> = MutableStateFlow(bar() * chad())
To make it simple, it can be done this way:

var a = MutableStateFlow(0)
fun bar() = a.value +1
fun chad() = 42
fun foo() = bar() * chad()

To make foo observable, it needs a setter or something to understand that needed value is current. Simple way is to make it variable:

val scope = CoroutineScope(Dispatchers.Default)

val foo = MutableStateFlow(bar() * chad())

init {
  scope.launch {
      a.collect {
          foo = bar() * chad()
      }
  }
}

Looks a little heavy especially with multiple vars in formula. Other suggestions?

Frankly speaking, I’m not sure what do you mean :slight_smile: If you mean to create a flow that will observe another flow for changes then all flow operators do exactly this, for example:

fun foo() = a.map { (it + 1) * chad() }
2 Likes

Hm, need to try. But how can I observe foo this way?

foo() returns a flow, so you just collect it. The main/only reason to have flows in the first place is to be able to observe something for new values - this is the main feature of flows. You can’t easily observe just any function for changing vales. You need flows for this (or another observable mechanism).

Is it fine to observe flow from Composable with .collectAsState() or need some wrappers?
According to this article, with flowWithLifecycle it’s possible to collect flows safely in Compose.

P.S. foo() also can be declared in the interface as

val foo: Flow
get() = a.map { (it + 1) * chad() }

It’s not related to flows but you could use observable - Kotlin Programming Language

1 Like

When I tried it last time, it was quite inconvenient.

What if I need to optimize and cache the calculations? It looks like, JVM doesn’t cache it by itself.
Also, is it possible to modify the Flow here to a MutableStateFlow to collect the value everywhere with a single line? Current in-model result looks like:

val foo: Flow
  get() = a.map { (it + 1) * chad() }

fun useFoo() = runBlocking {
    async(Dispatchers.Default) {
        foo.collect {
            something(it)
        }
    }.join()
}

It looks like last time I used Android’s Observable. But in this one I can’t find a difference with a simple setter. I can’t even .observe() it. What’s the purpose and how can it provide data to Composable?
What I need now - is alternative to Android’s LiveData that can be observed and changed anywhere without a coroutine with its observeForever().