Skip to content

//reactivestate-core/com.ensody.reactivestate/MutableValueFlow

MutableValueFlow

[common]\ interface MutableValueFlow<T> : ValueFlow<T> , MutableStateFlow<T>

A version of MutableStateFlow that provides better support for mutable values via the update operation. Assigning to .value still has distinctUntilChanged behavior, but emit/tryEmit and update always trigger a change event.

Example of mutating the value in-place:

flow.update {
    it.subvalue1.deepsubvalue.somevalue += 3
    it.subvalue2.state = SomeState.IN_PROGRESS
    it.isLoading = true
}

Why is this needed?

In Kotlin, working with nested immutable values (e.g. nested data class with val) is very unwieldy because you have to manually copy each element and its children:

flow.value = flow.value.let {
    it.copy(
        subvalue1 = it.subvalue1.copy(
            deepsubvalue = it.subvalue1.deepsubvalue.copy(somevalue = it.subvalue1.deepsubvalue.somevalue + 3)
         ),
        subvalue2 = it.subvalue2.copy(state = SomeState.IN_PROGRESS),
        isLoading = true,
    )
}

In many cases the UI state is even held in mutable data classes (with var), but doing the following would be unsafe with MutableStateFlow because the value is considered unchanged, so this code won’t trigger a UI update:

flow.value = flow.value.also {
    it.subvalue1.deepsubvalue.somevalue += 3
    it.subvalue2.state = SomeState.IN_PROGRESS
    it.isLoading = true
}

Kotlin just isn’t a pure functional language with built-in lens support and we have to deal with mutable values, so we should prevent overly complicated code with nested copy() and stupid mistakes like missing UI updates.

That’s why MutableValueFlow tries to make working with mutable values easy and safe.

Properties

Name Summary
replayCache [common]
abstract val replayCache: List<T>
subscriptionCount [common]
abstract val subscriptionCount: StateFlow<Int>
value [common]
abstract val value: T

Functions

Name Summary
addDelay [common]
fun <T> Flow<T>.addDelay(timeoutMillis: Long): Flow<T>
Adds a timeoutMillis delay to a Flow. If delay is zero or negative this is a no-op.
afterUpdate [common]
fun <T> MutableStateFlow<T>.afterUpdate(setter: (T) -> Unit): MutableStateFlow<T>
Returns a new MutableStateFlow that calls setter after doing the actual value update.
beforeUpdate [common]
fun <T> MutableStateFlow<T>.beforeUpdate(setter: (T) -> Unit): MutableStateFlow<T>
Returns a new MutableStateFlow that calls setter before doing the actual value update.
collect [common]
abstract suspend override fun collect(collector: FlowCollector<T>): Nothing
compareAndSet [common]
abstract fun compareAndSet(expect: T, update: T): Boolean
conflatedMap [common]
inline fun <T, R> Flow<T>.conflatedMap(timeoutMillis: Long = 0, crossinline transform: suspend (value: T) -> R): Flow<R>
Maps a conflated Flow with timeoutMillis delay between the first and last element.
conflatedTransform [common]
inline fun <T, R> Flow<T>.conflatedTransform(timeoutMillis: Long = 0, crossinline transform: suspend FlowCollector<R>.(value: T) -> Unit): Flow<R>
Transforms a conflated Flow with timeoutMillis delay between the first and last element.
conflatedWorker [common]
fun <T, R> Flow<T>.conflatedWorker(timeoutMillis: Long = 0, transform: FlowTransform<T, R>): Flow<R>
Executes each lambda in a Flow using conflatedMap.
debounceWorker [common]
fun <T, R> Flow<T>.debounceWorker(timeoutMillis: Long = 0, transform: FlowTransform<T, R>): Flow<R>
Executes each lambda in a Flow using debounce and map.
decrement [common]
fun MutableValueFlow<Int>.decrement(amount: Int = 1): Int
Atomically decrement this MutableValueFlow by amount.
emit [common]
abstract suspend override fun emit(value: T)
increment [common]
fun MutableValueFlow<Int>.increment(amount: Int = 1): Int
Atomically increment this MutableValueFlow by amount.
incrementFrom [common]
@JvmName(name = "incrementFromBoolean")
suspend fun MutableValueFlow<Int>.incrementFrom(flow: StateFlow<Boolean>)
suspend fun MutableValueFlow<Int>.incrementFrom(flow: StateFlow<Int>)
Keeps this incrementedincrement by the latest value in the given flow.
latestWorker [common]
fun <T, R> Flow<T>.latestWorker(timeoutMillis: Long = 0, transform: FlowTransform<T, R>): Flow<R>
Executes each lambda in a Flow using debounce and mapLatest.
onStateSubscription [common]
fun <T> MutableStateFlow<T>.onStateSubscription(block: suspend FlowCollector<T>.() -> Unit): MutableStateFlow<T>
Similar to MutableStateFlow.onSubscription but returns a MutableStateFlow.
[common]
fun <T> StateFlow<T>.onStateSubscription(block: suspend FlowCollector<T>.() -> Unit): StateFlow<T>
Similar to StateFlow.onSubscription but returns a StateFlow.
replace [common]
fun <T> MutableStateFlow<T>.replace(block: T.() -> T): T
Replaces the MutableStateFlow.value with block’s return value.
replaceLocked [common]
abstract fun replaceLocked(block: T.() -> T): T
Replaces the value with block’s return value. This is safe under concurrency.
resetReplayCache [common]
abstract fun resetReplayCache()
shareOnDemand [common]
fun <T> Flow<T>.shareOnDemand(replay: Int = 0, context: CoroutineContext = EmptyCoroutineContext): SharedFlow<T>
Turns this Flow into a SharedFlow without requiring a CoroutineScope (unlike shareIn).
stateOnDemand [common]
fun <T> Flow<T>.stateOnDemand(context: CoroutineContext = EmptyCoroutineContext, synchronous: Boolean = true, emitValueOnStart: Boolean = true, getter: (previous: Wrapped<T>?) -> T): StateFlow<T>
Turns this Flow into a StateFlow without requiring a CoroutineScope (unlike stateIn).
toMutable [common]
fun <T> StateFlow<T>.toMutable(setter: StateFlow<T>.(T) -> Unit): MutableStateFlow<T>
Converts this StateFlow to a MutableStateFlow that calls setter for doing the actual value update.
tryEmit [common]
abstract fun tryEmit(value: T): Boolean
update [common]
abstract fun update(block: (value: T) -> Unit)
Mutates value in-place and notifies listeners. The current value is passed as an arg.
updateThis [common]
open fun updateThis(block: T.() -> Unit)
Mutates value in-place and notifies listeners. The current value is passed via this.
withRefresh [common]
@ExperimentalReactiveStateApi
fun <T> MutableStateFlow<T>.withRefresh(block: suspend MutableStateFlow<T>.(force: Boolean) -> Unit): RefreshableStateFlow<T>
@ExperimentalReactiveStateApi
fun <T> StateFlow<T>.withRefresh(block: suspend StateFlow<T>.(force: Boolean) -> Unit): RefreshableStateFlow<T>
withSetter [common]
fun <T> MutableStateFlow<T>.withSetter(setter: MutableStateFlow<T>.(T) -> Unit): MutableStateFlow<T>
Returns a new MutableStateFlow that calls setter instead of doing the actual value update.