//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. |