SnapshotMutationPolicy
@JvmDefaultWithCompatibility
public interface SnapshotMutationPolicy<T>
A policy to control how the result of mutableStateOf
report and merge changes to the state
object.
A mutation policy can be passed as an parameter to mutableStateOf
, and compositionLocalOf
.
Typically, one of the stock policies should be used such as referentialEqualityPolicy
,
structuralEqualityPolicy
, or neverEqualPolicy
. However, a custom mutation policy can be
created by implementing this interface, such as a counter policy,
Functions
public fun equivalent(a: T, b: T): Boolean
Determine if setting a state value's are equivalent and should be treated as equal. If
equivalent
returns true
the new value is not considered a change.
public fun merge(previous: T, current: T, applied: T): T?
Merge conflicting changes in snapshots. This is only called if current
and applied
are
not equivalent
. If a valid merged value can be calculated then it should be returned.
For example, if the state object holds an immutable data class with multiple fields, and
applied
has changed fields that are unmodified by current
it might be valid to return a
new copy of the data class that combines that changes from both current
and applied
allowing a snapshot to apply that would have otherwise failed.
Code Examples
counterSample
fun counterSample() {
/**
* A policy that treats an `MutableState<Int>` as a counter. Changing the value to the same
* integer value will not be considered a change. When snapshots are applied the changes made by
* the applying snapshot are added together with changes of other snapshots. Changes to a
* [MutableState] with a counterPolicy will never cause an apply conflict.
*
* As the name implies, this is useful when counting things, such as tracking the amount of a
* resource consumed or produced while in a snapshot. For example, if snapshot A produces 10
* things and snapshot B produces 20 things, the result of applying both A and B should be that
* 30 things were produced.
*/
fun counterPolicy(): SnapshotMutationPolicy<Int> =
object : SnapshotMutationPolicy<Int> {
override fun equivalent(a: Int, b: Int): Boolean = a == b
override fun merge(previous: Int, current: Int, applied: Int) =
current + (applied - previous)
}
val state = mutableStateOf(0, counterPolicy())
val snapshot1 = Snapshot.takeMutableSnapshot()
val snapshot2 = Snapshot.takeMutableSnapshot()
try {
snapshot1.enter { state.value += 10 }
snapshot2.enter { state.value += 20 }
snapshot1.apply().check()
snapshot2.apply().check()
} finally {
snapshot1.dispose()
snapshot2.dispose()
}
// State is now equals 30 as the changes made in the snapshots are added together.
}