Oliver.O
11/17/2022, 3:00 PMSnapshotOliver.O
11/17/2022, 3:01 PMGlobalSnapshotManagerMutableStateclass TestFrontend {
    // ...
    fun launchIn(testScope: CoroutineScope) {
        GlobalSnapshotManager.ensureStarted()
        job = (testScope + Executors.newSingleThreadExecutor().asCoroutineDispatcher()).launch {
            withContext(SixtyFpsMonotonicFrameClock) {
                val viewTree = ViewNode()
                val recomposer = Recomposer(coroutineContext)
                val composition = Composition(ViewNode.Applier(viewTree), recomposer)
                try {
                    composition.setContent {
                        FrontendView(/* ... */) // uses LaunchedEffect to run backend communications
                    }
                    recomposer.runRecomposeAndApplyChanges()
                } finally {
                    composition.dispose()
                }
            }
        }
    }
    // ...
}MutableStateOliver.O
11/17/2022, 4:01 PMMutableStateOliver.O
11/17/2022, 10:31 PMMutableState@Composable
fun FrontendView(id: Int, testApplication: TestApplication) {
    val service = remember { TestFrontendService(id, testApplication) } // initializes MutableState
    LaunchedEffect(Unit) {
        withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
            service.launchIn(this) // changes MutableState
        }
    }
    // Composables accessing MutableState from service
}withContext(<http://Dispatchers.IO|Dispatchers.IO>)Oliver.O
11/17/2022, 10:46 PMThreadLocalZach Klippenstein (he/him) [MOD]
11/17/2022, 10:56 PMZach Klippenstein (he/him) [MOD]
11/17/2022, 11:07 PMOliver.O
11/17/2022, 11:12 PMGlobalSnapshotManagerobject GlobalSnapshotManager {
    private val started = AtomicBoolean(false)
    fun ensureStarted() {
        if (started.compareAndSet(false, true)) {
            val snapshotWriteObservation = Channel<Unit>(Channel.CONFLATED)
            CoroutineScope(singleThreadDispatcher()).launch {
                snapshotWriteObservation.consumeEach {
                    Snapshot.sendApplyNotifications()
                }
            }
            Snapshot.registerGlobalWriteObserver {
                logger.debug("write observed: $it")
                snapshotWriteObservation.trySend(Unit)
            }
        }
    }
}Oliver.O
11/17/2022, 11:17 PMConsider a network call made from aon theLaunchedEffectdispatcher that updates aIOwith the response. This code mutates a snapshot state value, without a snapshot, in a background thread (remember: Compose only wraps compositions in snapshots, and effects are executed outside of compositions).MutableState
Zach Klippenstein (he/him) [MOD]
11/17/2022, 11:21 PMOliver.O
11/17/2022, 11:27 PM