snapshotFlow

Function

Common
public fun <T> snapshotFlow(block: () -> T): Flow<T>

Create a Flow from observable Snapshot state. (e.g. state holders returned by mutableStateOf.)

snapshotFlow creates a Flow that runs block when collected and emits the result, recording any snapshot state that was accessed. While collection continues, if a new Snapshot is applied that changes state accessed by block, the flow will run block again, re-recording the snapshot state that was accessed. If the result of block is not equal to the previous result, the flow will emit that new result. (This behavior is similar to that of Flow.distinctUntilChanged.) Collection will continue indefinitely unless it is explicitly cancelled or limited by the use of other Flow operators.

block is run in a read-only Snapshot and may not modify snapshot data. If block attempts to modify snapshot data, flow collection will fail with IllegalStateException.

block may run more than once for equal sets of inputs or only once after many rapid snapshot changes; it should be idempotent and free of side effects.

When working with Snapshot state it is useful to keep the distinction between events and state in mind. snapshotFlow models snapshot changes as events, but events cannot be effectively modeled as observable state. Observable state is a lossy compression of the events that produced that state.

An observable event happens at a point in time and is discarded. All registered observers at the time the event occurred are notified. All individual events in a stream are assumed to be relevant and may build on one another; repeated equal events have meaning and therefore a registered observer must observe all events without skipping.

Observable state raises change events when the state changes from one value to a new, unequal value. State change events are conflated; only the most recent state matters. Observers of state changes must therefore be idempotent; given the same state value the observer should produce the same result. It is valid for a state observer to both skip intermediate states as well as run multiple times for the same state and the result should be the same.

Code Examples

snapshotFlowSample

@Suppress("UNREACHABLE_CODE", "CanBeVal", "UNUSED_VARIABLE")
fun snapshotFlowSample() {
    // Define Snapshot state objects
    var greeting by mutableStateOf("Hello")
    var person by mutableStateOf("Adam")
    // ...
    // Create a flow that will emit whenever our person-specific greeting changes
    val greetPersonFlow = snapshotFlow { "$greeting, $person" }
    // ...
    val collectionScope: CoroutineScope = TODO("Use your scope here")
    // Collect the flow and offer greetings!
    collectionScope.launch { greetPersonFlow.collect { println(greeting) } }
    // ...
    // Change snapshot state; greetPersonFlow will emit a new greeting
    Snapshot.withMutableSnapshot {
        greeting = "Ahoy"
        person = "Sean"
    }
}