Reactivity

A document exposes its changes as Flow, so a UI layer (or anything else) can react every time the stored value changes — no polling, no manual re-reads.

note.flow(): Flow<Note?>                  // cold; current value, then every committed write
note.stateFlow(scope): StateFlow<Note?>   // hot; shared while there are subscribers

flow()

flow() is cold: it hands you the current value the moment you collect, then a fresh value after each committed write. Emissions are conflated and fire only once a write is durably committed — writing a different document won't wake this one up. Deleting the document emits null:

note.flow().collect { current ->
    editor.render(current)
}

stateFlow(scope)

stateFlow(scope) is hot — it needs a CoroutineScope and stays shared while there are subscribers, which suits a ViewModel-owned stream that outlives any single collector.

Straight into Compose

val current by note.flow().collectAsStateWithLifecycle(initialValue = note.get())

current is nullable — null simply means the note hasn't been written yet.

How it works under the hood

MMKV has no native change-listener mechanism, so reactivity is a process-local concern: a single change bus emits the affected document's key after every committed write or delete, and flow() filters that bus for its own key and re-reads. See Reactivity Model for the full mechanism, including the important consequence that cross-process change notification is not provided.