DEV Community

Discussion on: Introduction to the Compose Snapshot system

 
gmk57 profile image
gmk57

Thanks for the detailed reply and for the warning about contention. It may be rare, but that means better chances of not catching it in tests and then having a rare crash with SnapshotApplyConflictException in production. ;)

So, to recap:

  • For atomic updates of single value (e.g. counter increments) from background thread we should use conflict-free data types and custom conflict resolver (SnapshotMutationPolicy).
  • To update atomically multiple related parts of state from background thread we should take an explicit snapshot and retry until success (like MutableStateFlow.update() does), for example:
fun <R> withSnapshotRetrying(block: () -> R): R {
    while (true) {
        try {
            return Snapshot.withMutableSnapshot(block)
        } catch (e: Exception) {
            if (e !is SnapshotApplyConflictException) throw e
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
  • But for doing the same things from the main thread we don't need an explicit snapshot, the changes will be atomic anyway (because global snapshot advancing happens on the main thread).
  • In case of multi-threaded composition all of the above remains true (Composables won't see any partial updates), because Compose wraps compositions in snapshots.

Correct?